I thought git would be smart enough to understand all the whitespace changes but even with all the flags I know to make it ignore theses it still blows up if there are identical changes on both sides.
I have a solution but it require creating a new commit at the merge base for each conflicting PR and merging it into develop.
I don't think blowing up all PRs is worth for now, maybe if we can coordinate this for V3 let's say.
This reverts commit 0d11331d18.
This commit is contained in:
@@ -4,40 +4,43 @@
|
||||
|
||||
static const String MESHTASTIC_OTA_APP_PROJECT_NAME("Meshtastic-OTA");
|
||||
|
||||
const esp_partition_t *BleOta::findEspOtaAppPartition() {
|
||||
const esp_partition_t *part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, nullptr);
|
||||
const esp_partition_t *BleOta::findEspOtaAppPartition()
|
||||
{
|
||||
const esp_partition_t *part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, nullptr);
|
||||
|
||||
esp_app_desc_t app_desc;
|
||||
esp_err_t ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc));
|
||||
esp_app_desc_t app_desc;
|
||||
esp_err_t ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc));
|
||||
|
||||
if (ret != ESP_OK || MESHTASTIC_OTA_APP_PROJECT_NAME != app_desc.project_name) {
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, nullptr);
|
||||
ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc));
|
||||
}
|
||||
if (ret != ESP_OK || MESHTASTIC_OTA_APP_PROJECT_NAME != app_desc.project_name) {
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, nullptr);
|
||||
ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc));
|
||||
}
|
||||
|
||||
if (ret == ESP_OK && MESHTASTIC_OTA_APP_PROJECT_NAME == app_desc.project_name) {
|
||||
return part;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
if (ret == ESP_OK && MESHTASTIC_OTA_APP_PROJECT_NAME == app_desc.project_name) {
|
||||
return part;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
String BleOta::getOtaAppVersion() {
|
||||
const esp_partition_t *part = findEspOtaAppPartition();
|
||||
esp_app_desc_t app_desc;
|
||||
esp_err_t ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc));
|
||||
String version;
|
||||
if (ret == ESP_OK) {
|
||||
version = app_desc.version;
|
||||
}
|
||||
return version;
|
||||
String BleOta::getOtaAppVersion()
|
||||
{
|
||||
const esp_partition_t *part = findEspOtaAppPartition();
|
||||
esp_app_desc_t app_desc;
|
||||
esp_err_t ret = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_get_partition_description(part, &app_desc));
|
||||
String version;
|
||||
if (ret == ESP_OK) {
|
||||
version = app_desc.version;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
bool BleOta::switchToOtaApp() {
|
||||
bool success = false;
|
||||
const esp_partition_t *part = findEspOtaAppPartition();
|
||||
if (part) {
|
||||
success = (ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_set_boot_partition(part)) == ESP_OK);
|
||||
}
|
||||
return success;
|
||||
bool BleOta::switchToOtaApp()
|
||||
{
|
||||
bool success = false;
|
||||
const esp_partition_t *part = findEspOtaAppPartition();
|
||||
if (part) {
|
||||
success = (ESP_ERROR_CHECK_WITHOUT_ABORT(esp_ota_set_boot_partition(part)) == ESP_OK);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -4,16 +4,17 @@
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
class BleOta {
|
||||
public:
|
||||
explicit BleOta(){};
|
||||
class BleOta
|
||||
{
|
||||
public:
|
||||
explicit BleOta(){};
|
||||
|
||||
static String getOtaAppVersion();
|
||||
static bool switchToOtaApp();
|
||||
static String getOtaAppVersion();
|
||||
static bool switchToOtaApp();
|
||||
|
||||
private:
|
||||
String mUserAgent;
|
||||
static const esp_partition_t *findEspOtaAppPartition();
|
||||
private:
|
||||
String mUserAgent;
|
||||
static const esp_partition_t *findEspOtaAppPartition();
|
||||
};
|
||||
|
||||
#endif // BLEOTA_H
|
||||
@@ -3,37 +3,39 @@
|
||||
|
||||
#include "mbedtls/aes.h"
|
||||
|
||||
class ESP32CryptoEngine : public CryptoEngine {
|
||||
class ESP32CryptoEngine : public CryptoEngine
|
||||
{
|
||||
|
||||
mbedtls_aes_context aes;
|
||||
mbedtls_aes_context aes;
|
||||
|
||||
public:
|
||||
ESP32CryptoEngine() { mbedtls_aes_init(&aes); }
|
||||
public:
|
||||
ESP32CryptoEngine() { mbedtls_aes_init(&aes); }
|
||||
|
||||
~ESP32CryptoEngine() { mbedtls_aes_free(&aes); }
|
||||
~ESP32CryptoEngine() { mbedtls_aes_free(&aes); }
|
||||
|
||||
/**
|
||||
* Encrypt a packet
|
||||
*
|
||||
* @param bytes is updated in place
|
||||
* TODO: return bool, and handle graciously when something fails
|
||||
*/
|
||||
virtual void encryptAESCtr(CryptoKey _key, uint8_t *_nonce, size_t numBytes, uint8_t *bytes) override {
|
||||
if (_key.length > 0) {
|
||||
if (numBytes <= MAX_BLOCKSIZE) {
|
||||
mbedtls_aes_setkey_enc(&aes, _key.bytes, _key.length * 8);
|
||||
static uint8_t scratch[MAX_BLOCKSIZE];
|
||||
uint8_t stream_block[16];
|
||||
size_t nc_off = 0;
|
||||
memcpy(scratch, bytes, numBytes);
|
||||
memset(scratch + numBytes, 0,
|
||||
sizeof(scratch) - numBytes); // Fill rest of buffer with zero (in case cypher looks at it)
|
||||
mbedtls_aes_crypt_ctr(&aes, numBytes, &nc_off, _nonce, stream_block, scratch, bytes);
|
||||
} else {
|
||||
LOG_ERROR("Packet too large for crypto engine: %d. noop encryption!", numBytes);
|
||||
}
|
||||
/**
|
||||
* Encrypt a packet
|
||||
*
|
||||
* @param bytes is updated in place
|
||||
* TODO: return bool, and handle graciously when something fails
|
||||
*/
|
||||
virtual void encryptAESCtr(CryptoKey _key, uint8_t *_nonce, size_t numBytes, uint8_t *bytes) override
|
||||
{
|
||||
if (_key.length > 0) {
|
||||
if (numBytes <= MAX_BLOCKSIZE) {
|
||||
mbedtls_aes_setkey_enc(&aes, _key.bytes, _key.length * 8);
|
||||
static uint8_t scratch[MAX_BLOCKSIZE];
|
||||
uint8_t stream_block[16];
|
||||
size_t nc_off = 0;
|
||||
memcpy(scratch, bytes, numBytes);
|
||||
memset(scratch + numBytes, 0,
|
||||
sizeof(scratch) - numBytes); // Fill rest of buffer with zero (in case cypher looks at it)
|
||||
mbedtls_aes_crypt_ctr(&aes, numBytes, &nc_off, _nonce, stream_block, scratch, bytes);
|
||||
} else {
|
||||
LOG_ERROR("Packet too large for crypto engine: %d. noop encryption!", numBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CryptoEngine *crypto = new ESP32CryptoEngine();
|
||||
@@ -2,17 +2,27 @@
|
||||
#include "assert.h"
|
||||
#include "configuration.h"
|
||||
|
||||
SimpleAllocator::SimpleAllocator() { reset(); }
|
||||
|
||||
void *SimpleAllocator::alloc(size_t size) {
|
||||
assert(nextFree + size <= sizeof(bytes));
|
||||
void *res = &bytes[nextFree];
|
||||
nextFree += size;
|
||||
LOG_DEBUG("Total simple allocs %u", nextFree);
|
||||
|
||||
return res;
|
||||
SimpleAllocator::SimpleAllocator()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void SimpleAllocator::reset() { nextFree = 0; }
|
||||
void *SimpleAllocator::alloc(size_t size)
|
||||
{
|
||||
assert(nextFree + size <= sizeof(bytes));
|
||||
void *res = &bytes[nextFree];
|
||||
nextFree += size;
|
||||
LOG_DEBUG("Total simple allocs %u", nextFree);
|
||||
|
||||
void *operator new(size_t size, SimpleAllocator &p) { return p.alloc(size); }
|
||||
return res;
|
||||
}
|
||||
|
||||
void SimpleAllocator::reset()
|
||||
{
|
||||
nextFree = 0;
|
||||
}
|
||||
|
||||
void *operator new(size_t size, SimpleAllocator &p)
|
||||
{
|
||||
return p.alloc(size);
|
||||
}
|
||||
|
||||
@@ -12,20 +12,21 @@
|
||||
* Currently the only usecase for this class is the ESP32 bluetooth stack, where once we've called deinit(false)
|
||||
* we are sure all those bluetooth objects no longer exist, and we'll need to recreate them when we restart bluetooth
|
||||
*/
|
||||
class SimpleAllocator {
|
||||
uint8_t bytes[POOL_SIZE] = {};
|
||||
class SimpleAllocator
|
||||
{
|
||||
uint8_t bytes[POOL_SIZE] = {};
|
||||
|
||||
uint32_t nextFree = 0;
|
||||
uint32_t nextFree = 0;
|
||||
|
||||
public:
|
||||
SimpleAllocator();
|
||||
public:
|
||||
SimpleAllocator();
|
||||
|
||||
void *alloc(size_t size);
|
||||
void *alloc(size_t size);
|
||||
|
||||
/** If you are _sure_ no outstanding references to blocks in this buffer still exist, you can call
|
||||
* reset() to start from scratch.
|
||||
* */
|
||||
void reset();
|
||||
/** If you are _sure_ no outstanding references to blocks in this buffer still exist, you can call
|
||||
* reset() to start from scratch.
|
||||
* */
|
||||
void reset();
|
||||
};
|
||||
|
||||
void *operator new(size_t size, SimpleAllocator &p);
|
||||
@@ -34,8 +35,9 @@ void *operator new(size_t size, SimpleAllocator &p);
|
||||
* Temporarily makes the specified Allocator be used for _all_ allocations. Useful when calling library routines
|
||||
* that don't know about pools
|
||||
*/
|
||||
class AllocatorScope {
|
||||
public:
|
||||
explicit AllocatorScope(SimpleAllocator &a);
|
||||
~AllocatorScope();
|
||||
class AllocatorScope
|
||||
{
|
||||
public:
|
||||
explicit AllocatorScope(SimpleAllocator &a);
|
||||
~AllocatorScope();
|
||||
};
|
||||
|
||||
@@ -3,77 +3,90 @@
|
||||
#include <Preferences.h>
|
||||
#include <esp_ota_ops.h>
|
||||
|
||||
namespace WiFiOTA {
|
||||
namespace WiFiOTA
|
||||
{
|
||||
|
||||
static const char *nvsNamespace = "ota-wifi";
|
||||
static const char *appProjectName = "OTA-WiFi";
|
||||
|
||||
static bool updated = false;
|
||||
|
||||
bool isUpdated() { return updated; }
|
||||
bool isUpdated()
|
||||
{
|
||||
return updated;
|
||||
}
|
||||
|
||||
void initialize() {
|
||||
Preferences prefs;
|
||||
prefs.begin(nvsNamespace);
|
||||
if (prefs.getBool("updated")) {
|
||||
LOG_INFO("First boot after OTA update");
|
||||
updated = true;
|
||||
void initialize()
|
||||
{
|
||||
Preferences prefs;
|
||||
prefs.begin(nvsNamespace);
|
||||
if (prefs.getBool("updated")) {
|
||||
LOG_INFO("First boot after OTA update");
|
||||
updated = true;
|
||||
prefs.putBool("updated", false);
|
||||
}
|
||||
prefs.end();
|
||||
}
|
||||
|
||||
void recoverConfig(meshtastic_Config_NetworkConfig *network)
|
||||
{
|
||||
LOG_INFO("Recovering WiFi settings after OTA update");
|
||||
|
||||
Preferences prefs;
|
||||
prefs.begin(nvsNamespace, true);
|
||||
String ssid = prefs.getString("ssid");
|
||||
String psk = prefs.getString("psk");
|
||||
prefs.end();
|
||||
|
||||
network->wifi_enabled = true;
|
||||
strncpy(network->wifi_ssid, ssid.c_str(), sizeof(network->wifi_ssid));
|
||||
strncpy(network->wifi_psk, psk.c_str(), sizeof(network->wifi_psk));
|
||||
}
|
||||
|
||||
void saveConfig(meshtastic_Config_NetworkConfig *network)
|
||||
{
|
||||
LOG_INFO("Saving WiFi settings for upcoming OTA update");
|
||||
|
||||
Preferences prefs;
|
||||
prefs.begin(nvsNamespace);
|
||||
prefs.putString("ssid", network->wifi_ssid);
|
||||
prefs.putString("psk", network->wifi_psk);
|
||||
prefs.putBool("updated", false);
|
||||
}
|
||||
prefs.end();
|
||||
prefs.end();
|
||||
}
|
||||
|
||||
void recoverConfig(meshtastic_Config_NetworkConfig *network) {
|
||||
LOG_INFO("Recovering WiFi settings after OTA update");
|
||||
|
||||
Preferences prefs;
|
||||
prefs.begin(nvsNamespace, true);
|
||||
String ssid = prefs.getString("ssid");
|
||||
String psk = prefs.getString("psk");
|
||||
prefs.end();
|
||||
|
||||
network->wifi_enabled = true;
|
||||
strncpy(network->wifi_ssid, ssid.c_str(), sizeof(network->wifi_ssid));
|
||||
strncpy(network->wifi_psk, psk.c_str(), sizeof(network->wifi_psk));
|
||||
const esp_partition_t *getAppPartition()
|
||||
{
|
||||
return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL);
|
||||
}
|
||||
|
||||
void saveConfig(meshtastic_Config_NetworkConfig *network) {
|
||||
LOG_INFO("Saving WiFi settings for upcoming OTA update");
|
||||
|
||||
Preferences prefs;
|
||||
prefs.begin(nvsNamespace);
|
||||
prefs.putString("ssid", network->wifi_ssid);
|
||||
prefs.putString("psk", network->wifi_psk);
|
||||
prefs.putBool("updated", false);
|
||||
prefs.end();
|
||||
bool getAppDesc(const esp_partition_t *part, esp_app_desc_t *app_desc)
|
||||
{
|
||||
if (esp_ota_get_partition_description(part, app_desc) != ESP_OK)
|
||||
return false;
|
||||
if (strcmp(app_desc->project_name, appProjectName) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
const esp_partition_t *getAppPartition() { return esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_1, NULL); }
|
||||
|
||||
bool getAppDesc(const esp_partition_t *part, esp_app_desc_t *app_desc) {
|
||||
if (esp_ota_get_partition_description(part, app_desc) != ESP_OK)
|
||||
return false;
|
||||
if (strcmp(app_desc->project_name, appProjectName) != 0)
|
||||
return false;
|
||||
return true;
|
||||
bool trySwitchToOTA()
|
||||
{
|
||||
const esp_partition_t *part = getAppPartition();
|
||||
esp_app_desc_t app_desc;
|
||||
if (!getAppDesc(part, &app_desc))
|
||||
return false;
|
||||
if (esp_ota_set_boot_partition(part) != ESP_OK)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool trySwitchToOTA() {
|
||||
const esp_partition_t *part = getAppPartition();
|
||||
esp_app_desc_t app_desc;
|
||||
if (!getAppDesc(part, &app_desc))
|
||||
return false;
|
||||
if (esp_ota_set_boot_partition(part) != ESP_OK)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *getVersion() {
|
||||
const esp_partition_t *part = getAppPartition();
|
||||
static esp_app_desc_t app_desc;
|
||||
if (!getAppDesc(part, &app_desc))
|
||||
return "";
|
||||
return app_desc.version;
|
||||
const char *getVersion()
|
||||
{
|
||||
const esp_partition_t *part = getAppPartition();
|
||||
static esp_app_desc_t app_desc;
|
||||
if (!getAppDesc(part, &app_desc))
|
||||
return "";
|
||||
return app_desc.version;
|
||||
}
|
||||
|
||||
} // namespace WiFiOTA
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
#include "mesh-pb-constants.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
namespace WiFiOTA {
|
||||
namespace WiFiOTA
|
||||
{
|
||||
void initialize();
|
||||
bool isUpdated();
|
||||
|
||||
|
||||
@@ -212,8 +212,8 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// If an SPI-related pin used by the LoRa module isn't defined, use the conventional pin number for it.
|
||||
// FIXME: these pins should really be defined in each variant.h file to prevent breakages if the defaults change,
|
||||
// currently many ESP32 variants don't define these pins in their variant.h file.
|
||||
// FIXME: these pins should really be defined in each variant.h file to prevent breakages if the defaults change, currently many
|
||||
// ESP32 variants don't define these pins in their variant.h file.
|
||||
#ifndef LORA_SCK
|
||||
#define LORA_SCK 5
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
|
||||
#define IRAM_SECTION section(".iram1.stub")
|
||||
|
||||
IRAM_ATTR esp_err_t stub_probe(esp_flash_t *chip, uint32_t flash_id) { return ESP_ERR_NOT_FOUND; }
|
||||
IRAM_ATTR esp_err_t stub_probe(esp_flash_t *chip, uint32_t flash_id)
|
||||
{
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
const spi_flash_chip_t stub_flash_chip __attribute__((IRAM_SECTION)) = {
|
||||
.name = "stub",
|
||||
|
||||
+149
-142
@@ -26,138 +26,143 @@
|
||||
#include <nvs_flash.h>
|
||||
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
void setBluetoothEnable(bool enable) {
|
||||
void setBluetoothEnable(bool enable)
|
||||
{
|
||||
#ifdef USE_WS5500
|
||||
if ((config.bluetooth.enabled == true) && (config.network.wifi_enabled == false))
|
||||
if ((config.bluetooth.enabled == true) && (config.network.wifi_enabled == false))
|
||||
#elif HAS_WIFI
|
||||
if (!isWifiAvailable() && config.bluetooth.enabled == true)
|
||||
if (!isWifiAvailable() && config.bluetooth.enabled == true)
|
||||
#else
|
||||
if (config.bluetooth.enabled == true)
|
||||
if (config.bluetooth.enabled == true)
|
||||
#endif
|
||||
{
|
||||
if (!nimbleBluetooth) {
|
||||
nimbleBluetooth = new NimbleBluetooth();
|
||||
{
|
||||
if (!nimbleBluetooth) {
|
||||
nimbleBluetooth = new NimbleBluetooth();
|
||||
}
|
||||
if (enable && !nimbleBluetooth->isActive()) {
|
||||
powerMon->setState(meshtastic_PowerMon_State_BT_On);
|
||||
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 (enable && !nimbleBluetooth->isActive()) {
|
||||
powerMon->setState(meshtastic_PowerMon_State_BT_On);
|
||||
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) {}
|
||||
void updateBatteryLevel(uint8_t level) {}
|
||||
#endif
|
||||
|
||||
void getMacAddr(uint8_t *dmac) {
|
||||
void getMacAddr(uint8_t *dmac)
|
||||
{
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C6) && defined(CONFIG_SOC_IEEE802154_SUPPORTED)
|
||||
auto res = esp_base_mac_addr_get(dmac);
|
||||
assert(res == ESP_OK);
|
||||
auto res = esp_base_mac_addr_get(dmac);
|
||||
assert(res == ESP_OK);
|
||||
#else
|
||||
auto res = esp_efuse_mac_get_default(dmac);
|
||||
assert(res == ESP_OK);
|
||||
auto res = esp_efuse_mac_get_default(dmac);
|
||||
assert(res == ESP_OK);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HAS_32768HZ
|
||||
#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)
|
||||
|
||||
static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name) {
|
||||
const uint32_t cal_count = 1000;
|
||||
// const float factor = (1 << 19) * 1000.0f; unused var?
|
||||
uint32_t cali_val;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
cali_val = rtc_clk_cal(cal_clk, cal_count);
|
||||
}
|
||||
return cali_val;
|
||||
static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name)
|
||||
{
|
||||
const uint32_t cal_count = 1000;
|
||||
// const float factor = (1 << 19) * 1000.0f; unused var?
|
||||
uint32_t cali_val;
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
cali_val = rtc_clk_cal(cal_clk, cal_count);
|
||||
}
|
||||
return cali_val;
|
||||
}
|
||||
|
||||
void enableSlowCLK() {
|
||||
rtc_clk_32k_enable(true);
|
||||
void enableSlowCLK()
|
||||
{
|
||||
rtc_clk_32k_enable(true);
|
||||
|
||||
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
|
||||
uint32_t cal_32k = CALIBRATE_ONE(RTC_CAL_32K_XTAL);
|
||||
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
|
||||
uint32_t cal_32k = CALIBRATE_ONE(RTC_CAL_32K_XTAL);
|
||||
|
||||
if (cal_32k == 0) {
|
||||
LOG_DEBUG("32k XTAL OSC has not started up");
|
||||
} else {
|
||||
rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
|
||||
LOG_DEBUG("Switch RTC Source to 32.768kHz succeeded, using 32k XTAL");
|
||||
if (cal_32k == 0) {
|
||||
LOG_DEBUG("32k XTAL OSC has not started up");
|
||||
} else {
|
||||
rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
|
||||
LOG_DEBUG("Switch RTC Source to 32.768kHz succeeded, using 32k XTAL");
|
||||
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
|
||||
CALIBRATE_ONE(RTC_CAL_32K_XTAL);
|
||||
}
|
||||
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
|
||||
CALIBRATE_ONE(RTC_CAL_32K_XTAL);
|
||||
}
|
||||
CALIBRATE_ONE(RTC_CAL_RTC_MUX);
|
||||
CALIBRATE_ONE(RTC_CAL_32K_XTAL);
|
||||
if (rtc_clk_slow_freq_get() != RTC_SLOW_FREQ_32K_XTAL) {
|
||||
LOG_WARN("Failed to switch 32K XTAL RTC source to 32.768kHz !!! ");
|
||||
return;
|
||||
}
|
||||
if (rtc_clk_slow_freq_get() != RTC_SLOW_FREQ_32K_XTAL) {
|
||||
LOG_WARN("Failed to switch 32K XTAL RTC source to 32.768kHz !!! ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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("Set random seed %u", seed);
|
||||
randomSeed(seed);
|
||||
*/
|
||||
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("Set random seed %u", seed);
|
||||
randomSeed(seed);
|
||||
*/
|
||||
|
||||
#ifdef ADC_V
|
||||
pinMode(ADC_V, INPUT);
|
||||
pinMode(ADC_V, INPUT);
|
||||
#endif
|
||||
|
||||
LOG_DEBUG("Total heap: %d", ESP.getHeapSize());
|
||||
LOG_DEBUG("Free heap: %d", ESP.getFreeHeap());
|
||||
LOG_DEBUG("Total PSRAM: %d", ESP.getPsramSize());
|
||||
LOG_DEBUG("Free PSRAM: %d", ESP.getFreePsram());
|
||||
LOG_DEBUG("Total heap: %d", ESP.getHeapSize());
|
||||
LOG_DEBUG("Free heap: %d", ESP.getFreeHeap());
|
||||
LOG_DEBUG("Total PSRAM: %d", ESP.getPsramSize());
|
||||
LOG_DEBUG("Free PSRAM: %d", ESP.getFreePsram());
|
||||
|
||||
nvs_stats_t nvs_stats;
|
||||
auto res = nvs_get_stats(NULL, &nvs_stats);
|
||||
assert(res == ESP_OK);
|
||||
LOG_DEBUG("NVS: UsedEntries %d, FreeEntries %d, AllEntries %d, NameSpaces %d", nvs_stats.used_entries, nvs_stats.free_entries,
|
||||
nvs_stats.total_entries, nvs_stats.namespace_count);
|
||||
nvs_stats_t nvs_stats;
|
||||
auto res = nvs_get_stats(NULL, &nvs_stats);
|
||||
assert(res == ESP_OK);
|
||||
LOG_DEBUG("NVS: UsedEntries %d, FreeEntries %d, AllEntries %d, NameSpaces %d", nvs_stats.used_entries, nvs_stats.free_entries,
|
||||
nvs_stats.total_entries, nvs_stats.namespace_count);
|
||||
|
||||
LOG_DEBUG("Setup Preferences in Flash Storage");
|
||||
LOG_DEBUG("Setup Preferences in Flash Storage");
|
||||
|
||||
// Create object to store our persistent data
|
||||
Preferences preferences;
|
||||
preferences.begin("meshtastic", false);
|
||||
// Create object to store our persistent data
|
||||
Preferences preferences;
|
||||
preferences.begin("meshtastic", false);
|
||||
|
||||
uint32_t rebootCounter = preferences.getUInt("rebootCounter", 0);
|
||||
rebootCounter++;
|
||||
preferences.putUInt("rebootCounter", rebootCounter);
|
||||
// store firmware version and hwrevision for access from OTA firmware
|
||||
String fwrev = preferences.getString("firmwareVersion", "");
|
||||
if (fwrev.compareTo(optstr(APP_VERSION)) != 0)
|
||||
preferences.putString("firmwareVersion", optstr(APP_VERSION));
|
||||
uint8_t hwven = preferences.getUInt("hwVendor", 0);
|
||||
if (hwven != HW_VENDOR)
|
||||
preferences.putUInt("hwVendor", HW_VENDOR);
|
||||
preferences.end();
|
||||
LOG_DEBUG("Number of Device Reboots: %d", rebootCounter);
|
||||
uint32_t rebootCounter = preferences.getUInt("rebootCounter", 0);
|
||||
rebootCounter++;
|
||||
preferences.putUInt("rebootCounter", rebootCounter);
|
||||
// store firmware version and hwrevision for access from OTA firmware
|
||||
String fwrev = preferences.getString("firmwareVersion", "");
|
||||
if (fwrev.compareTo(optstr(APP_VERSION)) != 0)
|
||||
preferences.putString("firmwareVersion", optstr(APP_VERSION));
|
||||
uint8_t hwven = preferences.getUInt("hwVendor", 0);
|
||||
if (hwven != HW_VENDOR)
|
||||
preferences.putUInt("hwVendor", HW_VENDOR);
|
||||
preferences.end();
|
||||
LOG_DEBUG("Number of Device Reboots: %d", rebootCounter);
|
||||
#if !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
String BLEOTA = BleOta::getOtaAppVersion();
|
||||
if (BLEOTA.isEmpty()) {
|
||||
LOG_INFO("No BLE OTA firmware available");
|
||||
} else {
|
||||
LOG_INFO("BLE OTA firmware version %s", BLEOTA.c_str());
|
||||
}
|
||||
String BLEOTA = BleOta::getOtaAppVersion();
|
||||
if (BLEOTA.isEmpty()) {
|
||||
LOG_INFO("No BLE OTA firmware available");
|
||||
} else {
|
||||
LOG_INFO("BLE OTA firmware version %s", BLEOTA.c_str());
|
||||
}
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_WIFI
|
||||
String version = WiFiOTA::getVersion();
|
||||
if (version.isEmpty()) {
|
||||
LOG_INFO("No WiFi OTA firmware available");
|
||||
} else {
|
||||
LOG_INFO("WiFi OTA firmware version %s", version.c_str());
|
||||
}
|
||||
WiFiOTA::initialize();
|
||||
String version = WiFiOTA::getVersion();
|
||||
if (version.isEmpty()) {
|
||||
LOG_INFO("No WiFi OTA firmware available");
|
||||
} else {
|
||||
LOG_INFO("WiFi OTA firmware version %s", version.c_str());
|
||||
}
|
||||
WiFiOTA::initialize();
|
||||
#endif
|
||||
|
||||
// enableModemSleep();
|
||||
// enableModemSleep();
|
||||
|
||||
// Since we are turning on watchdogs rather late in the release schedule, we really don't want to catch any
|
||||
// false positives. The wait-to-sleep timeout for shutting down radios is 30 secs, so pick 45 for now.
|
||||
@@ -165,96 +170,98 @@ void esp32Setup() {
|
||||
#define APP_WATCHDOG_SECS 90
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||
esp_task_wdt_config_t *wdt_config = (esp_task_wdt_config_t *)malloc(sizeof(esp_task_wdt_config_t));
|
||||
wdt_config->timeout_ms = APP_WATCHDOG_SECS * 1000;
|
||||
wdt_config->trigger_panic = true;
|
||||
res = esp_task_wdt_init(wdt_config);
|
||||
assert(res == ESP_OK);
|
||||
esp_task_wdt_config_t *wdt_config = (esp_task_wdt_config_t *)malloc(sizeof(esp_task_wdt_config_t));
|
||||
wdt_config->timeout_ms = APP_WATCHDOG_SECS * 1000;
|
||||
wdt_config->trigger_panic = true;
|
||||
res = esp_task_wdt_init(wdt_config);
|
||||
assert(res == ESP_OK);
|
||||
#else
|
||||
res = esp_task_wdt_init(APP_WATCHDOG_SECS, true);
|
||||
assert(res == ESP_OK);
|
||||
res = esp_task_wdt_init(APP_WATCHDOG_SECS, true);
|
||||
assert(res == ESP_OK);
|
||||
#endif
|
||||
res = esp_task_wdt_add(NULL);
|
||||
assert(res == ESP_OK);
|
||||
res = esp_task_wdt_add(NULL);
|
||||
assert(res == ESP_OK);
|
||||
|
||||
#if HAS_32768HZ
|
||||
enableSlowCLK();
|
||||
enableSlowCLK();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// loop code specific to ESP32 targets
|
||||
void esp32Loop() {
|
||||
esp_task_wdt_reset(); // service our app level watchdog
|
||||
void esp32Loop()
|
||||
{
|
||||
esp_task_wdt_reset(); // service our app level watchdog
|
||||
|
||||
// for debug printing
|
||||
// radio.radioIf.canSleep();
|
||||
// for debug printing
|
||||
// radio.radioIf.canSleep();
|
||||
}
|
||||
|
||||
void cpuDeepSleep(uint32_t msecToWake) {
|
||||
/*
|
||||
Some ESP32 IOs have internal pullups or pulldowns, which are enabled by default.
|
||||
If an external circuit drives this pin in deep sleep mode, current consumption may
|
||||
increase due to current flowing through these pullups and pulldowns.
|
||||
void cpuDeepSleep(uint32_t msecToWake)
|
||||
{
|
||||
/*
|
||||
Some ESP32 IOs have internal pullups or pulldowns, which are enabled by default.
|
||||
If an external circuit drives this pin in deep sleep mode, current consumption may
|
||||
increase due to current flowing through these pullups and pulldowns.
|
||||
|
||||
To isolate a pin, preventing extra current draw, call rtc_gpio_isolate() function.
|
||||
For example, on ESP32-WROVER module, GPIO12 is pulled up externally.
|
||||
GPIO12 also has an internal pulldown in the ESP32 chip. This means that in deep sleep,
|
||||
some current will flow through these external and internal resistors, increasing deep
|
||||
sleep current above the minimal possible value.
|
||||
To isolate a pin, preventing extra current draw, call rtc_gpio_isolate() function.
|
||||
For example, on ESP32-WROVER module, GPIO12 is pulled up externally.
|
||||
GPIO12 also has an internal pulldown in the ESP32 chip. This means that in deep sleep,
|
||||
some current will flow through these external and internal resistors, increasing deep
|
||||
sleep current above the minimal possible value.
|
||||
|
||||
Note: we don't isolate pins that are used for the LORA, LED, i2c, or ST7735 Display for the Chatter2, spi or the wake
|
||||
button(s), maybe we should not include any other GPIOs...
|
||||
*/
|
||||
Note: we don't isolate pins that are used for the LORA, LED, i2c, or ST7735 Display for the Chatter2, spi or the wake
|
||||
button(s), maybe we should not include any other GPIOs...
|
||||
*/
|
||||
#if SOC_RTCIO_HOLD_SUPPORTED
|
||||
static const uint8_t rtcGpios[] = {
|
||||
static const uint8_t rtcGpios[] = {
|
||||
#ifndef HELTEC_VISION_MASTER_E213
|
||||
// For this variant, >20mA leaks through the display if pin 2 held
|
||||
// Todo: check if it's safe to remove this pin for all variants
|
||||
2,
|
||||
// For this variant, >20mA leaks through the display if pin 2 held
|
||||
// Todo: check if it's safe to remove this pin for all variants
|
||||
2,
|
||||
#endif
|
||||
#ifndef USE_JTAG
|
||||
13,
|
||||
13,
|
||||
#endif
|
||||
34, 35, 37};
|
||||
34, 35, 37};
|
||||
|
||||
for (int i = 0; i < sizeof(rtcGpios); i++)
|
||||
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
|
||||
for (int i = 0; i < sizeof(rtcGpios); i++)
|
||||
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
|
||||
#endif
|
||||
|
||||
// FIXME, disable internal rtc pullups/pulldowns on the non isolated pins. for inputs that we aren't using
|
||||
// to detect wake and in normal operation the external part drives them hard.
|
||||
// FIXME, disable internal rtc pullups/pulldowns on the non isolated pins. for inputs that we aren't using
|
||||
// to detect wake and in normal operation the external part drives them hard.
|
||||
#ifdef BUTTON_PIN
|
||||
// Only GPIOs which are have RTC functionality can be used in this bit map: 0,2,4,12-15,25-27,32-39.
|
||||
// Only GPIOs which are have RTC functionality can be used in this bit map: 0,2,4,12-15,25-27,32-39.
|
||||
#if SOC_RTCIO_HOLD_SUPPORTED && SOC_PM_SUPPORT_EXT_WAKEUP
|
||||
uint64_t gpioMask = (1ULL << (config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
|
||||
uint64_t gpioMask = (1ULL << (config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
|
||||
#endif
|
||||
|
||||
#ifdef BUTTON_NEED_PULLUP
|
||||
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
||||
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
||||
#endif
|
||||
|
||||
// Not needed because both of the current boards have external pullups
|
||||
// FIXME change polarity in hw so we can wake on ANY_HIGH instead - that would allow us to use all three buttons
|
||||
// (instead of just the first) gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
||||
// Not needed because both of the current boards have external pullups
|
||||
// FIXME change polarity in hw so we can wake on ANY_HIGH instead - that would allow us to use all three buttons (instead
|
||||
// of just the first) gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
||||
|
||||
#ifdef ESP32S3_WAKE_TYPE
|
||||
esp_sleep_enable_ext1_wakeup(gpioMask, ESP32S3_WAKE_TYPE);
|
||||
esp_sleep_enable_ext1_wakeup(gpioMask, ESP32S3_WAKE_TYPE);
|
||||
#else
|
||||
#if SOC_PM_SUPPORT_EXT_WAKEUP
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
// ESP_EXT1_WAKEUP_ALL_LOW has been deprecated since esp-idf v5.4 for any other target.
|
||||
esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ALL_LOW);
|
||||
// ESP_EXT1_WAKEUP_ALL_LOW has been deprecated since esp-idf v5.4 for any other target.
|
||||
esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ALL_LOW);
|
||||
#else
|
||||
esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ANY_LOW);
|
||||
esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ANY_LOW);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // #end ESP32S3_WAKE_TYPE
|
||||
#endif
|
||||
|
||||
// We want RTC peripherals to stay on
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
// We want RTC peripherals to stay on
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
|
||||
esp_deep_sleep_start(); // TBD mA sleep current (battery)
|
||||
esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
|
||||
esp_deep_sleep_start(); // TBD mA sleep current (battery)
|
||||
}
|
||||
|
||||
@@ -7,33 +7,34 @@
|
||||
#include "graphics/TFTDisplay.h"
|
||||
|
||||
// Heltec tracker specific init
|
||||
void lateInitVariant() {
|
||||
// LOG_DEBUG("Heltec tracker initVariant");
|
||||
void lateInitVariant()
|
||||
{
|
||||
// LOG_DEBUG("Heltec tracker initVariant");
|
||||
|
||||
#ifndef MESHTASTIC_EXCLUDE_GPS
|
||||
GpioVirtPin *virtGpsEnable = gps ? gps->enablePin : new GpioVirtPin();
|
||||
GpioVirtPin *virtGpsEnable = gps ? gps->enablePin : new GpioVirtPin();
|
||||
#else
|
||||
GpioVirtPin *virtGpsEnable = new GpioVirtPin();
|
||||
GpioVirtPin *virtGpsEnable = new GpioVirtPin();
|
||||
#endif
|
||||
|
||||
#ifndef MESHTASTIC_EXCLUDE_SCREEN
|
||||
// On this board we are actually using the backlightEnable signal to already be controlling a physical enable to the
|
||||
// display controller. But we'd _ALSO_ like to have that signal drive a virtual GPIO. So nest it as needed.
|
||||
GpioVirtPin *virtScreenEnable = new GpioVirtPin();
|
||||
if (TFTDisplay::backlightEnable) {
|
||||
GpioPin *physScreenEnable = TFTDisplay::backlightEnable;
|
||||
GpioPin *splitter = new GpioSplitter(virtScreenEnable, physScreenEnable);
|
||||
TFTDisplay::backlightEnable = splitter;
|
||||
// On this board we are actually using the backlightEnable signal to already be controlling a physical enable to the
|
||||
// display controller. But we'd _ALSO_ like to have that signal drive a virtual GPIO. So nest it as needed.
|
||||
GpioVirtPin *virtScreenEnable = new GpioVirtPin();
|
||||
if (TFTDisplay::backlightEnable) {
|
||||
GpioPin *physScreenEnable = TFTDisplay::backlightEnable;
|
||||
GpioPin *splitter = new GpioSplitter(virtScreenEnable, physScreenEnable);
|
||||
TFTDisplay::backlightEnable = splitter;
|
||||
|
||||
// Assume screen is initially powered
|
||||
splitter->set(true);
|
||||
}
|
||||
// Assume screen is initially powered
|
||||
splitter->set(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(VEXT_ENABLE) && (!defined(MESHTASTIC_EXCLUDE_GPS) || !defined(MESHTASTIC_EXCLUDE_SCREEN))
|
||||
// If either the GPS or the screen is on, turn on the external power regulator
|
||||
GpioPin *hwEnable = new GpioHwPin(VEXT_ENABLE);
|
||||
new GpioBinaryTransformer(virtGpsEnable, virtScreenEnable, hwEnable, GpioBinaryTransformer::Or);
|
||||
// If either the GPS or the screen is on, turn on the external power regulator
|
||||
GpioPin *hwEnable = new GpioHwPin(VEXT_ENABLE);
|
||||
new GpioBinaryTransformer(virtGpsEnable, virtScreenEnable, hwEnable, GpioBinaryTransformer::Or);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -8,19 +8,21 @@
|
||||
|
||||
CSE_CST328 tsPanel = CSE_CST328(EINK_WIDTH, EINK_HEIGHT, &Wire, CST328_PIN_RST, CST328_PIN_INT);
|
||||
|
||||
bool readTouch(int16_t *x, int16_t *y) {
|
||||
if (tsPanel.getTouches()) {
|
||||
*x = tsPanel.getPoint(0).x;
|
||||
*y = tsPanel.getPoint(0).y;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
bool readTouch(int16_t *x, int16_t *y)
|
||||
{
|
||||
if (tsPanel.getTouches()) {
|
||||
*x = tsPanel.getPoint(0).x;
|
||||
*y = tsPanel.getPoint(0).y;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// T-Deck Pro specific init
|
||||
void lateInitVariant() {
|
||||
tsPanel.begin();
|
||||
touchScreenImpl1 = new TouchScreenImpl1(EINK_WIDTH, EINK_HEIGHT, readTouch);
|
||||
touchScreenImpl1->init();
|
||||
void lateInitVariant()
|
||||
{
|
||||
tsPanel.begin();
|
||||
touchScreenImpl1 = new TouchScreenImpl1(EINK_WIDTH, EINK_HEIGHT, readTouch);
|
||||
touchScreenImpl1->init();
|
||||
}
|
||||
#endif
|
||||
@@ -8,19 +8,20 @@ DriverPins PinsAudioBoardES8311;
|
||||
AudioBoard board(AudioDriverES8311, PinsAudioBoardES8311);
|
||||
|
||||
// TLora Pager specific init
|
||||
void lateInitVariant() {
|
||||
// AudioDriverLogger.begin(Serial, AudioDriverLogLevel::Debug);
|
||||
// I2C: function, scl, sda
|
||||
PinsAudioBoardES8311.addI2C(PinFunction::CODEC, Wire);
|
||||
// I2S: function, mclk, bck, ws, data_out, data_in
|
||||
PinsAudioBoardES8311.addI2S(PinFunction::CODEC, DAC_I2S_MCLK, DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT, DAC_I2S_DIN);
|
||||
void lateInitVariant()
|
||||
{
|
||||
// AudioDriverLogger.begin(Serial, AudioDriverLogLevel::Debug);
|
||||
// I2C: function, scl, sda
|
||||
PinsAudioBoardES8311.addI2C(PinFunction::CODEC, Wire);
|
||||
// I2S: function, mclk, bck, ws, data_out, data_in
|
||||
PinsAudioBoardES8311.addI2S(PinFunction::CODEC, DAC_I2S_MCLK, DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT, DAC_I2S_DIN);
|
||||
|
||||
// configure codec
|
||||
CodecConfig cfg;
|
||||
cfg.input_device = ADC_INPUT_LINE1;
|
||||
cfg.output_device = DAC_OUTPUT_ALL;
|
||||
cfg.i2s.bits = BIT_LENGTH_16BITS;
|
||||
cfg.i2s.rate = RATE_44K;
|
||||
board.begin(cfg);
|
||||
// configure codec
|
||||
CodecConfig cfg;
|
||||
cfg.input_device = ADC_INPUT_LINE1;
|
||||
cfg.output_device = DAC_OUTPUT_ALL;
|
||||
cfg.i2s.bits = BIT_LENGTH_16BITS;
|
||||
cfg.i2s.rate = RATE_44K;
|
||||
board.begin(cfg);
|
||||
}
|
||||
#endif
|
||||
@@ -10,32 +10,34 @@ TouchDrvCSTXXX tsPanel;
|
||||
static constexpr uint8_t PossibleAddresses[2] = {CST328_ADDR, CST226SE_ADDR_ALT};
|
||||
uint8_t i2cAddress = 0;
|
||||
|
||||
bool readTouch(int16_t *x, int16_t *y) {
|
||||
int16_t x_array[1], y_array[1];
|
||||
uint8_t touched = tsPanel.getPoint(x_array, y_array, 1);
|
||||
if (touched > 0) {
|
||||
*y = x_array[0];
|
||||
*x = (TFT_WIDTH - y_array[0]);
|
||||
// Check bounds
|
||||
if (*x < 0 || *x >= TFT_WIDTH || *y < 0 || *y >= TFT_HEIGHT) {
|
||||
return false;
|
||||
bool readTouch(int16_t *x, int16_t *y)
|
||||
{
|
||||
int16_t x_array[1], y_array[1];
|
||||
uint8_t touched = tsPanel.getPoint(x_array, y_array, 1);
|
||||
if (touched > 0) {
|
||||
*y = x_array[0];
|
||||
*x = (TFT_WIDTH - y_array[0]);
|
||||
// Check bounds
|
||||
if (*x < 0 || *x >= TFT_WIDTH || *y < 0 || *y >= TFT_HEIGHT) {
|
||||
return false;
|
||||
}
|
||||
return true; // Valid touch detected
|
||||
}
|
||||
return true; // Valid touch detected
|
||||
}
|
||||
return false; // No valid touch data
|
||||
return false; // No valid touch data
|
||||
}
|
||||
|
||||
void lateInitVariant() {
|
||||
tsPanel.setTouchDrvModel(TouchDrv_CST226);
|
||||
for (uint8_t addr : PossibleAddresses) {
|
||||
if (tsPanel.begin(Wire, addr, I2C_SDA, I2C_SCL)) {
|
||||
i2cAddress = addr;
|
||||
LOG_DEBUG("CST226SE init OK at address 0x%02X", addr);
|
||||
touchScreenImpl1 = new TouchScreenImpl1(TFT_WIDTH, TFT_HEIGHT, readTouch);
|
||||
touchScreenImpl1->init();
|
||||
return;
|
||||
void lateInitVariant()
|
||||
{
|
||||
tsPanel.setTouchDrvModel(TouchDrv_CST226);
|
||||
for (uint8_t addr : PossibleAddresses) {
|
||||
if (tsPanel.begin(Wire, addr, I2C_SDA, I2C_SCL)) {
|
||||
i2cAddress = addr;
|
||||
LOG_DEBUG("CST226SE init OK at address 0x%02X", addr);
|
||||
touchScreenImpl1 = new TouchScreenImpl1(TFT_WIDTH, TFT_HEIGHT, readTouch);
|
||||
touchScreenImpl1->init();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_ERROR("CST226SE init failed at all known addresses");
|
||||
LOG_ERROR("CST226SE init failed at all known addresses");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4,48 +4,70 @@
|
||||
|
||||
AsyncUDP::AsyncUDP() : OSThread("AsyncUDP"), localPort(0) {}
|
||||
|
||||
bool AsyncUDP::listenMulticast(IPAddress multicastIP, uint16_t port, uint8_t ttl) {
|
||||
if (!isMulticast(multicastIP))
|
||||
return false;
|
||||
localPort = port;
|
||||
udp.beginMulticast(multicastIP, port);
|
||||
return true;
|
||||
bool AsyncUDP::listenMulticast(IPAddress multicastIP, uint16_t port, uint8_t ttl)
|
||||
{
|
||||
if (!isMulticast(multicastIP))
|
||||
return false;
|
||||
localPort = port;
|
||||
udp.beginMulticast(multicastIP, port);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t AsyncUDP::write(uint8_t b) { return udp.write(&b, 1); }
|
||||
size_t AsyncUDP::write(uint8_t b)
|
||||
{
|
||||
return udp.write(&b, 1);
|
||||
}
|
||||
|
||||
size_t AsyncUDP::write(const uint8_t *data, size_t len) { return udp.write(data, len); }
|
||||
size_t AsyncUDP::write(const uint8_t *data, size_t len)
|
||||
{
|
||||
return udp.write(data, len);
|
||||
}
|
||||
|
||||
void AsyncUDP::onPacket(const std::function<void(AsyncUDPPacket)> &callback) { _onPacket = callback; }
|
||||
void AsyncUDP::onPacket(const std::function<void(AsyncUDPPacket)> &callback)
|
||||
{
|
||||
_onPacket = callback;
|
||||
}
|
||||
|
||||
bool AsyncUDP::writeTo(const uint8_t *data, size_t len, IPAddress ip, uint16_t port) {
|
||||
if (!udp.beginPacket(ip, port))
|
||||
return false;
|
||||
udp.write(data, len);
|
||||
return udp.endPacket();
|
||||
bool AsyncUDP::writeTo(const uint8_t *data, size_t len, IPAddress ip, uint16_t port)
|
||||
{
|
||||
if (!udp.beginPacket(ip, port))
|
||||
return false;
|
||||
udp.write(data, len);
|
||||
return udp.endPacket();
|
||||
}
|
||||
|
||||
// AsyncUDPPacket
|
||||
AsyncUDPPacket::AsyncUDPPacket(EthernetUDP &source) : _udp(source), _remoteIP(source.remoteIP()), _remotePort(source.remotePort()) {
|
||||
if (_udp.available() > 0) {
|
||||
_readLength = _udp.read(_buffer, sizeof(_buffer));
|
||||
} else {
|
||||
_readLength = 0;
|
||||
}
|
||||
AsyncUDPPacket::AsyncUDPPacket(EthernetUDP &source) : _udp(source), _remoteIP(source.remoteIP()), _remotePort(source.remotePort())
|
||||
{
|
||||
if (_udp.available() > 0) {
|
||||
_readLength = _udp.read(_buffer, sizeof(_buffer));
|
||||
} else {
|
||||
_readLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
IPAddress AsyncUDPPacket::remoteIP() { return _remoteIP; }
|
||||
IPAddress AsyncUDPPacket::remoteIP()
|
||||
{
|
||||
return _remoteIP;
|
||||
}
|
||||
|
||||
uint16_t AsyncUDPPacket::length() { return _readLength; }
|
||||
uint16_t AsyncUDPPacket::length()
|
||||
{
|
||||
return _readLength;
|
||||
}
|
||||
|
||||
const uint8_t *AsyncUDPPacket::data() { return _buffer; }
|
||||
const uint8_t *AsyncUDPPacket::data()
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
int32_t AsyncUDP::runOnce() {
|
||||
if (_onPacket && udp.parsePacket() > 0) {
|
||||
AsyncUDPPacket packet(udp);
|
||||
_onPacket(packet);
|
||||
}
|
||||
return 5; // check every 5ms
|
||||
int32_t AsyncUDP::runOnce()
|
||||
{
|
||||
if (_onPacket && udp.parsePacket() > 0) {
|
||||
AsyncUDPPacket packet(udp);
|
||||
_onPacket(packet);
|
||||
}
|
||||
return 5; // check every 5ms
|
||||
}
|
||||
|
||||
#endif // HAS_ETHERNET
|
||||
@@ -14,44 +14,49 @@
|
||||
|
||||
class AsyncUDPPacket;
|
||||
|
||||
class AsyncUDP : public Print, private concurrency::OSThread {
|
||||
public:
|
||||
AsyncUDP();
|
||||
explicit operator bool() const { return localPort != 0; }
|
||||
class AsyncUDP : public Print, private concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
AsyncUDP();
|
||||
explicit operator bool() const { return localPort != 0; }
|
||||
|
||||
bool listenMulticast(IPAddress multicastIP, uint16_t port, uint8_t ttl = 64);
|
||||
bool writeTo(const uint8_t *data, size_t len, IPAddress ip, uint16_t port);
|
||||
bool listenMulticast(IPAddress multicastIP, uint16_t port, uint8_t ttl = 64);
|
||||
bool writeTo(const uint8_t *data, size_t len, IPAddress ip, uint16_t port);
|
||||
|
||||
size_t write(uint8_t b) override;
|
||||
size_t write(const uint8_t *data, size_t len) override;
|
||||
void onPacket(const std::function<void(AsyncUDPPacket)> &callback);
|
||||
size_t write(uint8_t b) override;
|
||||
size_t write(const uint8_t *data, size_t len) override;
|
||||
void onPacket(const std::function<void(AsyncUDPPacket)> &callback);
|
||||
|
||||
private:
|
||||
EthernetUDP udp;
|
||||
uint16_t localPort;
|
||||
std::function<void(AsyncUDPPacket)> _onPacket;
|
||||
virtual int32_t runOnce() override;
|
||||
private:
|
||||
EthernetUDP udp;
|
||||
uint16_t localPort;
|
||||
std::function<void(AsyncUDPPacket)> _onPacket;
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
class AsyncUDPPacket {
|
||||
public:
|
||||
AsyncUDPPacket(EthernetUDP &source);
|
||||
class AsyncUDPPacket
|
||||
{
|
||||
public:
|
||||
AsyncUDPPacket(EthernetUDP &source);
|
||||
|
||||
IPAddress remoteIP();
|
||||
uint16_t length();
|
||||
const uint8_t *data();
|
||||
IPAddress remoteIP();
|
||||
uint16_t length();
|
||||
const uint8_t *data();
|
||||
|
||||
private:
|
||||
EthernetUDP &_udp;
|
||||
IPAddress _remoteIP;
|
||||
uint16_t _remotePort;
|
||||
size_t _readLength = 0;
|
||||
private:
|
||||
EthernetUDP &_udp;
|
||||
IPAddress _remoteIP;
|
||||
uint16_t _remotePort;
|
||||
size_t _readLength = 0;
|
||||
|
||||
static constexpr size_t BUF_SIZE = 512;
|
||||
uint8_t _buffer[BUF_SIZE];
|
||||
static constexpr size_t BUF_SIZE = 512;
|
||||
uint8_t _buffer[BUF_SIZE];
|
||||
};
|
||||
|
||||
inline bool isMulticast(const IPAddress &ip) { return (ip[0] & 0xF0) == 0xE0; }
|
||||
inline bool isMulticast(const IPAddress &ip)
|
||||
{
|
||||
return (ip[0] & 0xF0) == 0xE0;
|
||||
}
|
||||
|
||||
#endif // HAS_ETHERNET
|
||||
|
||||
|
||||
@@ -41,99 +41,103 @@
|
||||
|
||||
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};
|
||||
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) {
|
||||
uint16_t crc = 0xFFFF;
|
||||
static uint16_t crc16(const uint8_t *data_p, uint8_t length)
|
||||
{
|
||||
uint16_t crc = 0xFFFF;
|
||||
|
||||
while (length--) {
|
||||
uint8_t x = crc >> 8 ^ *data_p++;
|
||||
x ^= x >> 4;
|
||||
crc = (crc << 8) ^ ((uint16_t)(x << 12)) ^ ((uint16_t)(x << 5)) ^ ((uint16_t)x);
|
||||
}
|
||||
return crc;
|
||||
while (length--) {
|
||||
uint8_t 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);
|
||||
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};
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate crc
|
||||
peer_data->crc16 = crc16((uint8_t *)peer_data, offsetof(peer_data_t, crc16));
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
|
||||
|
||||
// Initiate DFU Sequence and reboot into DFU OTA mode
|
||||
Bluefruit.Advertising.restartOnDisconnect(false);
|
||||
conn->disconnect();
|
||||
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;
|
||||
|
||||
NRF_POWER->GPREGRET = 0xB1;
|
||||
NVIC_SystemReset();
|
||||
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());
|
||||
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());
|
||||
_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;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
@@ -41,14 +41,15 @@
|
||||
#include "BLECharacteristic.h"
|
||||
#include "BLEService.h"
|
||||
|
||||
class BLEDfuSecure : public BLEService {
|
||||
protected:
|
||||
BLECharacteristic _chr_control;
|
||||
class BLEDfuSecure : public BLEService
|
||||
{
|
||||
protected:
|
||||
BLECharacteristic _chr_control;
|
||||
|
||||
public:
|
||||
BLEDfuSecure(void);
|
||||
public:
|
||||
BLEDfuSecure(void);
|
||||
|
||||
virtual err_t begin(void);
|
||||
virtual err_t begin(void);
|
||||
};
|
||||
|
||||
#endif /* BLEDFUSECURE_H_ */
|
||||
|
||||
@@ -19,12 +19,12 @@ 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
|
||||
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 process at once static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size),
|
||||
// MyNodeInfo_size), FromRadio_size)];
|
||||
// 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)];
|
||||
static uint8_t fromRadioBytes[meshtastic_FromRadio_size];
|
||||
static uint8_t toRadioBytes[meshtastic_ToRadio_size];
|
||||
|
||||
@@ -33,372 +33,403 @@ static uint8_t lastToRadio[MAX_TO_FROM_RADIO_SIZE];
|
||||
|
||||
static uint16_t connectionHandle;
|
||||
|
||||
class BluetoothPhoneAPI : public PhoneAPI {
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
virtual void onNowHasData(uint32_t fromRadioNum) override {
|
||||
PhoneAPI::onNowHasData(fromRadioNum);
|
||||
class BluetoothPhoneAPI : public PhoneAPI
|
||||
{
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
virtual void onNowHasData(uint32_t fromRadioNum) override
|
||||
{
|
||||
PhoneAPI::onNowHasData(fromRadioNum);
|
||||
|
||||
LOG_INFO("BLE notify fromNum");
|
||||
fromNum.notify32(fromRadioNum);
|
||||
}
|
||||
LOG_INFO("BLE notify fromNum");
|
||||
fromNum.notify32(fromRadioNum);
|
||||
}
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() override { return Bluefruit.connected(connectionHandle); }
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() override { return Bluefruit.connected(connectionHandle); }
|
||||
|
||||
public:
|
||||
BluetoothPhoneAPI() { api_type = TYPE_BLE; }
|
||||
public:
|
||||
BluetoothPhoneAPI() { api_type = TYPE_BLE; }
|
||||
};
|
||||
|
||||
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", central_name);
|
||||
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", central_name);
|
||||
|
||||
// Notify UI (or any other interested firmware components)
|
||||
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::CONNECTED);
|
||||
bluetoothStatus->updateStatus(&newStatus);
|
||||
// Notify UI (or any other interested firmware components)
|
||||
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::CONNECTED);
|
||||
bluetoothStatus->updateStatus(&newStatus);
|
||||
}
|
||||
/**
|
||||
* Callback invoked when a connection is dropped
|
||||
* @param conn_handle connection where this event happens
|
||||
* @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
|
||||
*/
|
||||
void onDisconnect(uint16_t conn_handle, uint8_t reason) {
|
||||
LOG_INFO("BLE Disconnected, reason = 0x%x", reason);
|
||||
if (bluetoothPhoneAPI) {
|
||||
bluetoothPhoneAPI->close();
|
||||
}
|
||||
|
||||
// Clear the last ToRadio packet buffer to avoid rejecting first packet from new connection
|
||||
memset(lastToRadio, 0, sizeof(lastToRadio));
|
||||
|
||||
// Notify UI (or any other interested firmware components)
|
||||
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED);
|
||||
bluetoothStatus->updateStatus(&newStatus);
|
||||
}
|
||||
void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value) {
|
||||
// Display the raw request packet
|
||||
LOG_INFO("CCCD Updated: %u", 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");
|
||||
} else {
|
||||
LOG_INFO("Notify/Indicate disabled");
|
||||
void onDisconnect(uint16_t conn_handle, uint8_t reason)
|
||||
{
|
||||
LOG_INFO("BLE Disconnected, reason = 0x%x", reason);
|
||||
if (bluetoothPhoneAPI) {
|
||||
bluetoothPhoneAPI->close();
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the last ToRadio packet buffer to avoid rejecting first packet from new connection
|
||||
memset(lastToRadio, 0, sizeof(lastToRadio));
|
||||
|
||||
// Notify UI (or any other interested firmware components)
|
||||
meshtastic::BluetoothStatus newStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED);
|
||||
bluetoothStatus->updateStatus(&newStatus);
|
||||
}
|
||||
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
|
||||
* - Timeout for fast mode is 30 seconds
|
||||
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
|
||||
*
|
||||
* For recommended advertising interval
|
||||
* https://developer.apple.com/library/content/qa/qa1931/_index.html
|
||||
*/
|
||||
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
||||
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
|
||||
void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value)
|
||||
{
|
||||
// Display the raw request packet
|
||||
LOG_INFO("CCCD Updated: %u", 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");
|
||||
} else {
|
||||
LOG_INFO("Notify/Indicate disabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
* - Timeout for fast mode is 30 seconds
|
||||
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
|
||||
*
|
||||
* For recommended advertising interval
|
||||
* https://developer.apple.com/library/content/qa/qa1931/_index.html
|
||||
*/
|
||||
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
||||
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) {
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {.type = BLE_GATTS_AUTHORIZE_TYPE_READ};
|
||||
reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
|
||||
sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply);
|
||||
static void authorizeRead(uint16_t conn_hdl)
|
||||
{
|
||||
ble_gatts_rw_authorize_reply_params_t reply = {.type = BLE_GATTS_AUTHORIZE_TYPE_READ};
|
||||
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
|
||||
*/
|
||||
void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request) {
|
||||
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);
|
||||
} else {
|
||||
// LOG_INFO("Ignore successor read");
|
||||
}
|
||||
authorizeRead(conn_hdl);
|
||||
void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request)
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
// LOG_INFO("Ignore successor read");
|
||||
}
|
||||
authorizeRead(conn_hdl);
|
||||
}
|
||||
|
||||
void onToRadioWrite(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len) {
|
||||
LOG_INFO("toRadioWriteCb data %p, len %u", data, len);
|
||||
if (memcmp(lastToRadio, data, len) != 0) {
|
||||
LOG_DEBUG("New ToRadio packet");
|
||||
memcpy(lastToRadio, data, len);
|
||||
bluetoothPhoneAPI->handleToRadio(data, len);
|
||||
} else {
|
||||
LOG_DEBUG("Drop dup ToRadio packet we just saw");
|
||||
}
|
||||
void onToRadioWrite(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len)
|
||||
{
|
||||
LOG_INFO("toRadioWriteCb data %p, len %u", data, len);
|
||||
if (memcmp(lastToRadio, data, len) != 0) {
|
||||
LOG_DEBUG("New ToRadio packet");
|
||||
memcpy(lastToRadio, data, len);
|
||||
bluetoothPhoneAPI->handleToRadio(data, len);
|
||||
} else {
|
||||
LOG_DEBUG("Drop dup ToRadio packet we just saw");
|
||||
}
|
||||
}
|
||||
|
||||
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(0); // Variable len (either 0 or 4) FIXME consider changing protocol so it is fixed 4 byte len,
|
||||
// where 0 means empty
|
||||
fromNum.setMaxLen(4);
|
||||
fromNum.setCccdWriteCallback(onCccd); // Optionally capture CCCD updates
|
||||
// We don't yet need to hook the fromNum auth callback
|
||||
// fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb);
|
||||
fromNum.write32(0); // Provide default fromNum of 0
|
||||
fromNum.begin();
|
||||
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(
|
||||
0); // Variable len (either 0 or 4) FIXME consider changing protocol so it is fixed 4 byte len, where 0 means empty
|
||||
fromNum.setMaxLen(4);
|
||||
fromNum.setCccdWriteCallback(onCccd); // Optionally capture CCCD updates
|
||||
// We don't yet need to hook the fromNum auth callback
|
||||
// fromNum.setReadAuthorizeCallback(fromNumAuthorizeCb);
|
||||
fromNum.write32(0); // Provide default fromNum of 0
|
||||
fromNum.begin();
|
||||
|
||||
fromRadio.setProperties(CHR_PROPS_READ);
|
||||
fromRadio.setPermission(secMode, SECMODE_NO_ACCESS);
|
||||
fromRadio.setMaxLen(sizeof(fromRadioBytes));
|
||||
fromRadio.setReadAuthorizeCallback(onFromRadioAuthorize,
|
||||
false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
|
||||
fromRadio.setBuffer(fromRadioBytes,
|
||||
sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space
|
||||
// for two copies
|
||||
fromRadio.begin();
|
||||
fromRadio.setProperties(CHR_PROPS_READ);
|
||||
fromRadio.setPermission(secMode, SECMODE_NO_ACCESS);
|
||||
fromRadio.setMaxLen(sizeof(fromRadioBytes));
|
||||
fromRadio.setReadAuthorizeCallback(
|
||||
onFromRadioAuthorize,
|
||||
false); // We don't call this callback via the adafruit queue, because we can safely run in the BLE context
|
||||
fromRadio.setBuffer(fromRadioBytes, sizeof(fromRadioBytes)); // we preallocate our fromradio buffer so we won't waste space
|
||||
// for two copies
|
||||
fromRadio.begin();
|
||||
|
||||
toRadio.setProperties(CHR_PROPS_WRITE);
|
||||
toRadio.setPermission(secMode, secMode); // FIXME secure this!
|
||||
toRadio.setFixedLen(0);
|
||||
toRadio.setMaxLen(512);
|
||||
toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes));
|
||||
// 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();
|
||||
toRadio.setProperties(CHR_PROPS_WRITE);
|
||||
toRadio.setPermission(secMode, secMode); // FIXME secure this!
|
||||
toRadio.setFixedLen(0);
|
||||
toRadio.setMaxLen(512);
|
||||
toRadio.setBuffer(toRadioBytes, sizeof(toRadioBytes));
|
||||
// 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();
|
||||
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
|
||||
LOG_INFO("Disable NRF52 bluetooth");
|
||||
Bluefruit.Security.setPairPasskeyCallback(NRF52Bluetooth::onUnwantedPairing); // Actively refuse (during factory reset)
|
||||
disconnect();
|
||||
Bluefruit.Advertising.stop();
|
||||
void NRF52Bluetooth::shutdown()
|
||||
{
|
||||
// Shutdown bluetooth for minimum power draw
|
||||
LOG_INFO("Disable NRF52 bluetooth");
|
||||
Bluefruit.Security.setPairPasskeyCallback(NRF52Bluetooth::onUnwantedPairing); // Actively refuse (during factory reset)
|
||||
disconnect();
|
||||
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("Disable NRF52 Bluetooth. (Workaround: tx power min, advertise stopped)");
|
||||
void NRF52Bluetooth::startDisabled()
|
||||
{
|
||||
// Setup Bluetooth
|
||||
nrf52Bluetooth->setup();
|
||||
// Shutdown bluetooth for minimum power draw
|
||||
Bluefruit.Advertising.stop();
|
||||
Bluefruit.setTxPower(-40); // Minimum power
|
||||
LOG_INFO("Disable NRF52 Bluetooth. (Workaround: tx power min, advertise stopped)");
|
||||
}
|
||||
bool NRF52Bluetooth::isConnected() { return Bluefruit.connected(connectionHandle); }
|
||||
int NRF52Bluetooth::getRssi() {
|
||||
return 0; // FIXME figure out where to source this
|
||||
bool NRF52Bluetooth::isConnected()
|
||||
{
|
||||
return Bluefruit.connected(connectionHandle);
|
||||
}
|
||||
void NRF52Bluetooth::setup() {
|
||||
// Initialise the Bluefruit module
|
||||
LOG_INFO("Init the Bluefruit nRF52 module");
|
||||
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 : random(100000, 999999);
|
||||
auto pinString = std::to_string(configuredPasskey);
|
||||
LOG_INFO("Bluetooth pin set to '%i'", configuredPasskey);
|
||||
Bluefruit.Security.setPIN(pinString.c_str());
|
||||
Bluefruit.Security.setIOCaps(true, false, false);
|
||||
Bluefruit.Security.setPairPasskeyCallback(NRF52Bluetooth::onPairingPasskey);
|
||||
Bluefruit.Security.setPairCompleteCallback(NRF52Bluetooth::onPairingCompleted);
|
||||
Bluefruit.Security.setSecuredCallback(NRF52Bluetooth::onConnectionSecured);
|
||||
meshBleService.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
|
||||
} else {
|
||||
Bluefruit.Security.setIOCaps(false, false, false);
|
||||
meshBleService.setPermission(SECMODE_OPEN, SECMODE_OPEN);
|
||||
}
|
||||
// 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);
|
||||
int NRF52Bluetooth::getRssi()
|
||||
{
|
||||
return 0; // FIXME figure out where to source this
|
||||
}
|
||||
void NRF52Bluetooth::setup()
|
||||
{
|
||||
// Initialise the Bluefruit module
|
||||
LOG_INFO("Init the Bluefruit nRF52 module");
|
||||
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
|
||||
: random(100000, 999999);
|
||||
auto pinString = std::to_string(configuredPasskey);
|
||||
LOG_INFO("Bluetooth pin set to '%i'", configuredPasskey);
|
||||
Bluefruit.Security.setPIN(pinString.c_str());
|
||||
Bluefruit.Security.setIOCaps(true, false, false);
|
||||
Bluefruit.Security.setPairPasskeyCallback(NRF52Bluetooth::onPairingPasskey);
|
||||
Bluefruit.Security.setPairCompleteCallback(NRF52Bluetooth::onPairingCompleted);
|
||||
Bluefruit.Security.setSecuredCallback(NRF52Bluetooth::onConnectionSecured);
|
||||
meshBleService.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
|
||||
} else {
|
||||
Bluefruit.Security.setIOCaps(false, false, false);
|
||||
meshBleService.setPermission(SECMODE_OPEN, SECMODE_OPEN);
|
||||
}
|
||||
// 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);
|
||||
#ifndef BLE_DFU_SECURE
|
||||
bledfu.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
|
||||
bledfu.begin(); // Install the DFU helper
|
||||
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
|
||||
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("Init the Device Information Service");
|
||||
bledis.setModel(optstr(HW_VERSION));
|
||||
bledis.setFirmwareRev(optstr(APP_VERSION));
|
||||
bledis.begin();
|
||||
// Start the BLE Battery Service and set it to 100%
|
||||
LOG_INFO("Init the Battery Service");
|
||||
blebas.begin();
|
||||
blebas.write(0); // Unknown battery level for now
|
||||
// Setup the Heart Rate Monitor service using
|
||||
// BLEService and BLECharacteristic classes
|
||||
LOG_INFO("Init the Mesh bluetooth service");
|
||||
setupMeshService();
|
||||
// Setup the advertising packet(s)
|
||||
LOG_INFO("Set up the advertising payload(s)");
|
||||
startAdv();
|
||||
LOG_INFO("Advertise");
|
||||
// Configure and Start the Device Information Service
|
||||
LOG_INFO("Init the Device Information Service");
|
||||
bledis.setModel(optstr(HW_VERSION));
|
||||
bledis.setFirmwareRev(optstr(APP_VERSION));
|
||||
bledis.begin();
|
||||
// Start the BLE Battery Service and set it to 100%
|
||||
LOG_INFO("Init the Battery Service");
|
||||
blebas.begin();
|
||||
blebas.write(0); // Unknown battery level for now
|
||||
// Setup the Heart Rate Monitor service using
|
||||
// BLEService and BLECharacteristic classes
|
||||
LOG_INFO("Init the Mesh bluetooth service");
|
||||
setupMeshService();
|
||||
// Setup the advertising packet(s)
|
||||
LOG_INFO("Set up the advertising payload(s)");
|
||||
startAdv();
|
||||
LOG_INFO("Advertise");
|
||||
}
|
||||
void NRF52Bluetooth::resumeAdvertising() {
|
||||
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||
Bluefruit.Advertising.start(0);
|
||||
void NRF52Bluetooth::resumeAdvertising()
|
||||
{
|
||||
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
||||
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("Clear bluetooth bonds!");
|
||||
bond_print_list(BLE_GAP_ROLE_PERIPH);
|
||||
bond_print_list(BLE_GAP_ROLE_CENTRAL);
|
||||
Bluefruit.Periph.clearBonds();
|
||||
Bluefruit.Central.clearBonds();
|
||||
void updateBatteryLevel(uint8_t level)
|
||||
{
|
||||
blebas.write(level);
|
||||
}
|
||||
void NRF52Bluetooth::onConnectionSecured(uint16_t conn_handle) { LOG_INFO("BLE connection secured"); }
|
||||
bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) {
|
||||
char passkey1[4] = {passkey[0], passkey[1], passkey[2], '\0'};
|
||||
char passkey2[4] = {passkey[3], passkey[4], passkey[5], '\0'};
|
||||
LOG_INFO("BLE pair process started with passkey %s %s", passkey1, passkey2);
|
||||
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
|
||||
void NRF52Bluetooth::clearBonds()
|
||||
{
|
||||
LOG_INFO("Clear bluetooth bonds!");
|
||||
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");
|
||||
}
|
||||
bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request)
|
||||
{
|
||||
char passkey1[4] = {passkey[0], passkey[1], passkey[2], '\0'};
|
||||
char passkey2[4] = {passkey[3], passkey[4], passkey[5], '\0'};
|
||||
LOG_INFO("BLE pair process started with passkey %s %s", passkey1, passkey2);
|
||||
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
|
||||
|
||||
// Get passkey as string
|
||||
// Note: possible leading zeros
|
||||
std::string textkey;
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
textkey += (char)passkey[i];
|
||||
// Get passkey as string
|
||||
// Note: possible leading zeros
|
||||
std::string textkey;
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
textkey += (char)passkey[i];
|
||||
|
||||
// Notify UI (or other components) of pairing event and passkey
|
||||
meshtastic::BluetoothStatus newStatus(textkey);
|
||||
bluetoothStatus->updateStatus(&newStatus);
|
||||
// Notify UI (or other components) of pairing event and passkey
|
||||
meshtastic::BluetoothStatus newStatus(textkey);
|
||||
bluetoothStatus->updateStatus(&newStatus);
|
||||
|
||||
#if HAS_SCREEN && !defined(MESHTASTIC_EXCLUDE_SCREEN) // Todo: migrate this display code back into Screen class, and
|
||||
// observe bluetoothStatus
|
||||
if (screen) {
|
||||
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 : 12;
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(x_offset + x, y_offset + y, "Bluetooth");
|
||||
#if HAS_SCREEN && \
|
||||
!defined(MESHTASTIC_EXCLUDE_SCREEN) // Todo: migrate this display code back into Screen class, and observe bluetoothStatus
|
||||
if (screen) {
|
||||
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 : 12;
|
||||
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_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_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
|
||||
if (match_request) {
|
||||
uint32_t start_time = millis();
|
||||
while (millis() < start_time + 30000) {
|
||||
if (!Bluefruit.connected(conn_handle))
|
||||
break;
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
LOG_INFO("BLE passkey pair: match_request=%i", match_request);
|
||||
return true;
|
||||
#endif
|
||||
if (match_request) {
|
||||
uint32_t start_time = millis();
|
||||
while (millis() < start_time + 30000) {
|
||||
if (!Bluefruit.connected(conn_handle))
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG_INFO("BLE passkey pair: match_request=%i", match_request);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Actively refuse new BLE pairings
|
||||
// After clearing bonds (at factory reset), clients seem initially able to attempt to re-pair, even with advertising
|
||||
// disabled. On NRF52Bluetooth::shutdown, we change the pairing callback to this method, to aggressively refuse any
|
||||
// connection attempts.
|
||||
bool NRF52Bluetooth::onUnwantedPairing(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) {
|
||||
NRF52Bluetooth::disconnect();
|
||||
return false;
|
||||
// After clearing bonds (at factory reset), clients seem initially able to attempt to re-pair, even with advertising disabled.
|
||||
// On NRF52Bluetooth::shutdown, we change the pairing callback to this method, to aggressively refuse any connection attempts.
|
||||
bool NRF52Bluetooth::onUnwantedPairing(uint16_t conn_handle, uint8_t const passkey[6], bool match_request)
|
||||
{
|
||||
NRF52Bluetooth::disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disconnect any BLE connections
|
||||
void NRF52Bluetooth::disconnect() {
|
||||
uint8_t connection_num = Bluefruit.connected();
|
||||
if (connection_num) {
|
||||
// Close all connections. We're only expecting one.
|
||||
for (uint8_t i = 0; i < connection_num; i++)
|
||||
Bluefruit.disconnect(i);
|
||||
void NRF52Bluetooth::disconnect()
|
||||
{
|
||||
uint8_t connection_num = Bluefruit.connected();
|
||||
if (connection_num) {
|
||||
// Close all connections. We're only expecting one.
|
||||
for (uint8_t i = 0; i < connection_num; i++)
|
||||
Bluefruit.disconnect(i);
|
||||
|
||||
// Wait for disconnection
|
||||
while (Bluefruit.connected())
|
||||
yield();
|
||||
// Wait for disconnection
|
||||
while (Bluefruit.connected())
|
||||
yield();
|
||||
|
||||
LOG_INFO("Ended BLE connection");
|
||||
}
|
||||
LOG_INFO("Ended BLE connection");
|
||||
}
|
||||
}
|
||||
|
||||
void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_status) {
|
||||
if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) {
|
||||
LOG_INFO("BLE pair success");
|
||||
meshtastic::BluetoothStatus newConnectedStatus(meshtastic::BluetoothStatus::ConnectionState::CONNECTED);
|
||||
bluetoothStatus->updateStatus(&newConnectedStatus);
|
||||
} else {
|
||||
LOG_INFO("BLE pair failed");
|
||||
// Notify UI (or any other interested firmware components)
|
||||
meshtastic::BluetoothStatus newDisconnectedStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED);
|
||||
bluetoothStatus->updateStatus(&newDisconnectedStatus);
|
||||
}
|
||||
void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_status)
|
||||
{
|
||||
if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) {
|
||||
LOG_INFO("BLE pair success");
|
||||
meshtastic::BluetoothStatus newConnectedStatus(meshtastic::BluetoothStatus::ConnectionState::CONNECTED);
|
||||
bluetoothStatus->updateStatus(&newConnectedStatus);
|
||||
} else {
|
||||
LOG_INFO("BLE pair failed");
|
||||
// Notify UI (or any other interested firmware components)
|
||||
meshtastic::BluetoothStatus newDisconnectedStatus(meshtastic::BluetoothStatus::ConnectionState::DISCONNECTED);
|
||||
bluetoothStatus->updateStatus(&newDisconnectedStatus);
|
||||
}
|
||||
|
||||
// Todo: migrate this display code back into Screen class, and observe bluetoothStatus
|
||||
if (screen) {
|
||||
screen->endAlert();
|
||||
}
|
||||
// Todo: migrate this display code back into Screen class, and observe bluetoothStatus
|
||||
if (screen) {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
@@ -3,22 +3,23 @@
|
||||
#include "BluetoothCommon.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
class NRF52Bluetooth : BluetoothApi {
|
||||
public:
|
||||
void setup();
|
||||
void shutdown();
|
||||
void startDisabled();
|
||||
void resumeAdvertising();
|
||||
void clearBonds();
|
||||
bool isConnected();
|
||||
int getRssi();
|
||||
void sendLog(const uint8_t *logMessage, size_t length);
|
||||
class NRF52Bluetooth : BluetoothApi
|
||||
{
|
||||
public:
|
||||
void setup();
|
||||
void shutdown();
|
||||
void startDisabled();
|
||||
void resumeAdvertising();
|
||||
void clearBonds();
|
||||
bool isConnected();
|
||||
int getRssi();
|
||||
void sendLog(const uint8_t *logMessage, size_t length);
|
||||
|
||||
private:
|
||||
static void onConnectionSecured(uint16_t conn_handle);
|
||||
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);
|
||||
private:
|
||||
static void onConnectionSecured(uint16_t conn_handle);
|
||||
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);
|
||||
|
||||
static bool onUnwantedPairing(uint16_t conn_handle, uint8_t const passkey[6], bool match_request);
|
||||
static void disconnect();
|
||||
static bool onUnwantedPairing(uint16_t conn_handle, uint8_t const passkey[6], bool match_request);
|
||||
static void disconnect();
|
||||
};
|
||||
@@ -2,29 +2,31 @@
|
||||
#include "aes-256/tiny-aes.h"
|
||||
#include "configuration.h"
|
||||
#include <Adafruit_nRFCrypto.h>
|
||||
class NRF52CryptoEngine : public CryptoEngine {
|
||||
public:
|
||||
NRF52CryptoEngine() {}
|
||||
class NRF52CryptoEngine : public CryptoEngine
|
||||
{
|
||||
public:
|
||||
NRF52CryptoEngine() {}
|
||||
|
||||
~NRF52CryptoEngine() {}
|
||||
~NRF52CryptoEngine() {}
|
||||
|
||||
virtual void encryptAESCtr(CryptoKey _key, uint8_t *_nonce, size_t numBytes, uint8_t *bytes) override {
|
||||
if (_key.length > 16) {
|
||||
AES_ctx ctx;
|
||||
AES_init_ctx_iv(&ctx, _key.bytes, _nonce);
|
||||
AES_CTR_xcrypt_buffer(&ctx, bytes, numBytes);
|
||||
} else if (_key.length > 0) {
|
||||
nRFCrypto.begin();
|
||||
nRFCrypto_AES ctx;
|
||||
uint8_t myLen = ctx.blockLen(numBytes);
|
||||
char encBuf[myLen] = {0};
|
||||
ctx.begin();
|
||||
ctx.Process((char *)bytes, numBytes, _nonce, _key.bytes, _key.length, encBuf, ctx.encryptFlag, ctx.ctrMode);
|
||||
ctx.end();
|
||||
nRFCrypto.end();
|
||||
memcpy(bytes, encBuf, numBytes);
|
||||
virtual void encryptAESCtr(CryptoKey _key, uint8_t *_nonce, size_t numBytes, uint8_t *bytes) override
|
||||
{
|
||||
if (_key.length > 16) {
|
||||
AES_ctx ctx;
|
||||
AES_init_ctx_iv(&ctx, _key.bytes, _nonce);
|
||||
AES_CTR_xcrypt_buffer(&ctx, bytes, numBytes);
|
||||
} else if (_key.length > 0) {
|
||||
nRFCrypto.begin();
|
||||
nRFCrypto_AES ctx;
|
||||
uint8_t myLen = ctx.blockLen(numBytes);
|
||||
char encBuf[myLen] = {0};
|
||||
ctx.begin();
|
||||
ctx.Process((char *)bytes, numBytes, _nonce, _key.bytes, _key.length, encBuf, ctx.encryptFlag, ctx.ctrMode);
|
||||
ctx.end();
|
||||
nRFCrypto.end();
|
||||
memcpy(bytes, encBuf, numBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CryptoEngine *crypto = new NRF52CryptoEngine();
|
||||
@@ -19,179 +19,198 @@ typedef uint8_t state_t[4][4];
|
||||
|
||||
static const uint8_t sbox[256] = {
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
|
||||
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
|
||||
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
|
||||
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
|
||||
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
|
||||
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d,
|
||||
0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
|
||||
0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
|
||||
0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb,
|
||||
0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
|
||||
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d,
|
||||
0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
|
||||
0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
|
||||
0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9,
|
||||
0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
|
||||
|
||||
static const uint8_t Rcon[11] = {0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
|
||||
|
||||
#define getSBoxValue(num) (sbox[(num)])
|
||||
|
||||
static void KeyExpansion(uint8_t *RoundKey, const uint8_t *Key) {
|
||||
uint8_t tempa[4];
|
||||
static void KeyExpansion(uint8_t *RoundKey, const uint8_t *Key)
|
||||
{
|
||||
uint8_t tempa[4];
|
||||
|
||||
for (unsigned i = 0; i < Nk; ++i) {
|
||||
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
|
||||
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
|
||||
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
|
||||
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
|
||||
}
|
||||
|
||||
for (unsigned i = Nk; i < Nb * (Nr + 1); ++i) {
|
||||
unsigned k = (i - 1) * 4;
|
||||
tempa[0] = RoundKey[k + 0];
|
||||
tempa[1] = RoundKey[k + 1];
|
||||
tempa[2] = RoundKey[k + 2];
|
||||
tempa[3] = RoundKey[k + 3];
|
||||
|
||||
if (i % Nk == 0) {
|
||||
const uint8_t u8tmp = tempa[0];
|
||||
tempa[0] = tempa[1];
|
||||
tempa[1] = tempa[2];
|
||||
tempa[2] = tempa[3];
|
||||
tempa[3] = u8tmp;
|
||||
|
||||
tempa[0] = getSBoxValue(tempa[0]);
|
||||
tempa[1] = getSBoxValue(tempa[1]);
|
||||
tempa[2] = getSBoxValue(tempa[2]);
|
||||
tempa[3] = getSBoxValue(tempa[3]);
|
||||
|
||||
tempa[0] = tempa[0] ^ Rcon[i / Nk];
|
||||
for (unsigned i = 0; i < Nk; ++i) {
|
||||
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
|
||||
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
|
||||
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
|
||||
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
|
||||
}
|
||||
|
||||
if (i % Nk == 4) {
|
||||
tempa[0] = getSBoxValue(tempa[0]);
|
||||
tempa[1] = getSBoxValue(tempa[1]);
|
||||
tempa[2] = getSBoxValue(tempa[2]);
|
||||
tempa[3] = getSBoxValue(tempa[3]);
|
||||
}
|
||||
for (unsigned i = Nk; i < Nb * (Nr + 1); ++i) {
|
||||
unsigned k = (i - 1) * 4;
|
||||
tempa[0] = RoundKey[k + 0];
|
||||
tempa[1] = RoundKey[k + 1];
|
||||
tempa[2] = RoundKey[k + 2];
|
||||
tempa[3] = RoundKey[k + 3];
|
||||
|
||||
unsigned j = i * 4;
|
||||
k = (i - Nk) * 4;
|
||||
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
|
||||
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
|
||||
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
|
||||
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
|
||||
}
|
||||
}
|
||||
if (i % Nk == 0) {
|
||||
const uint8_t u8tmp = tempa[0];
|
||||
tempa[0] = tempa[1];
|
||||
tempa[1] = tempa[2];
|
||||
tempa[2] = tempa[3];
|
||||
tempa[3] = u8tmp;
|
||||
|
||||
void AES_init_ctx(struct AES_ctx *ctx, const uint8_t *key) { KeyExpansion(ctx->RoundKey, key); }
|
||||
void AES_init_ctx_iv(struct AES_ctx *ctx, const uint8_t *key, const uint8_t *iv) {
|
||||
KeyExpansion(ctx->RoundKey, key);
|
||||
memcpy(ctx->Iv, iv, AES_BLOCKLEN);
|
||||
}
|
||||
void AES_ctx_set_iv(struct AES_ctx *ctx, const uint8_t *iv) { memcpy(ctx->Iv, iv, AES_BLOCKLEN); }
|
||||
tempa[0] = getSBoxValue(tempa[0]);
|
||||
tempa[1] = getSBoxValue(tempa[1]);
|
||||
tempa[2] = getSBoxValue(tempa[2]);
|
||||
tempa[3] = getSBoxValue(tempa[3]);
|
||||
|
||||
static void AddRoundKey(uint8_t round, state_t *state, const uint8_t *RoundKey) {
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
for (uint8_t j = 0; j < 4; ++j) {
|
||||
(*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SubBytes(state_t *state) {
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
for (uint8_t j = 0; j < 4; ++j) {
|
||||
(*state)[j][i] = getSBoxValue((*state)[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ShiftRows(state_t *state) {
|
||||
uint8_t temp = (*state)[0][1];
|
||||
(*state)[0][1] = (*state)[1][1];
|
||||
(*state)[1][1] = (*state)[2][1];
|
||||
(*state)[2][1] = (*state)[3][1];
|
||||
(*state)[3][1] = temp;
|
||||
|
||||
temp = (*state)[0][2];
|
||||
(*state)[0][2] = (*state)[2][2];
|
||||
(*state)[2][2] = temp;
|
||||
|
||||
temp = (*state)[1][2];
|
||||
(*state)[1][2] = (*state)[3][2];
|
||||
(*state)[3][2] = temp;
|
||||
|
||||
temp = (*state)[0][3];
|
||||
(*state)[0][3] = (*state)[3][3];
|
||||
(*state)[3][3] = (*state)[2][3];
|
||||
(*state)[2][3] = (*state)[1][3];
|
||||
(*state)[1][3] = temp;
|
||||
}
|
||||
|
||||
static uint8_t xtime(uint8_t x) { return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)); }
|
||||
|
||||
static void MixColumns(state_t *state) {
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
uint8_t t = (*state)[i][0];
|
||||
uint8_t Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3];
|
||||
uint8_t Tm = (*state)[i][0] ^ (*state)[i][1];
|
||||
Tm = xtime(Tm);
|
||||
(*state)[i][0] ^= Tm ^ Tmp;
|
||||
Tm = (*state)[i][1] ^ (*state)[i][2];
|
||||
Tm = xtime(Tm);
|
||||
(*state)[i][1] ^= Tm ^ Tmp;
|
||||
Tm = (*state)[i][2] ^ (*state)[i][3];
|
||||
Tm = xtime(Tm);
|
||||
(*state)[i][2] ^= Tm ^ Tmp;
|
||||
Tm = (*state)[i][3] ^ t;
|
||||
Tm = xtime(Tm);
|
||||
(*state)[i][3] ^= Tm ^ Tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#define Multiply(x, y) \
|
||||
(((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ ((y >> 2 & 1) * xtime(xtime(x))) ^ ((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ \
|
||||
((y >> 4 & 1) * xtime(xtime(xtime(xtime(x))))))
|
||||
|
||||
static void Cipher(state_t *state, const uint8_t *RoundKey) {
|
||||
uint8_t round = 0;
|
||||
|
||||
AddRoundKey(0, state, RoundKey);
|
||||
|
||||
for (round = 1;; ++round) {
|
||||
SubBytes(state);
|
||||
ShiftRows(state);
|
||||
if (round == Nr) {
|
||||
break;
|
||||
}
|
||||
MixColumns(state);
|
||||
AddRoundKey(round, state, RoundKey);
|
||||
}
|
||||
AddRoundKey(Nr, state, RoundKey);
|
||||
}
|
||||
|
||||
void AES_CTR_xcrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, size_t length) {
|
||||
uint8_t buffer[AES_BLOCKLEN];
|
||||
|
||||
size_t i;
|
||||
int bi;
|
||||
for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) {
|
||||
if (bi == AES_BLOCKLEN) {
|
||||
|
||||
memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
|
||||
Cipher((state_t *)buffer, ctx->RoundKey);
|
||||
|
||||
for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) {
|
||||
if (ctx->Iv[bi] == 255) {
|
||||
ctx->Iv[bi] = 0;
|
||||
continue;
|
||||
tempa[0] = tempa[0] ^ Rcon[i / Nk];
|
||||
}
|
||||
ctx->Iv[bi] += 1;
|
||||
break;
|
||||
}
|
||||
bi = 0;
|
||||
}
|
||||
|
||||
buf[i] = (buf[i] ^ buffer[bi]);
|
||||
}
|
||||
if (i % Nk == 4) {
|
||||
tempa[0] = getSBoxValue(tempa[0]);
|
||||
tempa[1] = getSBoxValue(tempa[1]);
|
||||
tempa[2] = getSBoxValue(tempa[2]);
|
||||
tempa[3] = getSBoxValue(tempa[3]);
|
||||
}
|
||||
|
||||
unsigned j = i * 4;
|
||||
k = (i - Nk) * 4;
|
||||
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
|
||||
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
|
||||
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
|
||||
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
|
||||
}
|
||||
}
|
||||
|
||||
void AES_init_ctx(struct AES_ctx *ctx, const uint8_t *key)
|
||||
{
|
||||
KeyExpansion(ctx->RoundKey, key);
|
||||
}
|
||||
void AES_init_ctx_iv(struct AES_ctx *ctx, const uint8_t *key, const uint8_t *iv)
|
||||
{
|
||||
KeyExpansion(ctx->RoundKey, key);
|
||||
memcpy(ctx->Iv, iv, AES_BLOCKLEN);
|
||||
}
|
||||
void AES_ctx_set_iv(struct AES_ctx *ctx, const uint8_t *iv)
|
||||
{
|
||||
memcpy(ctx->Iv, iv, AES_BLOCKLEN);
|
||||
}
|
||||
|
||||
static void AddRoundKey(uint8_t round, state_t *state, const uint8_t *RoundKey)
|
||||
{
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
for (uint8_t j = 0; j < 4; ++j) {
|
||||
(*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SubBytes(state_t *state)
|
||||
{
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
for (uint8_t j = 0; j < 4; ++j) {
|
||||
(*state)[j][i] = getSBoxValue((*state)[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ShiftRows(state_t *state)
|
||||
{
|
||||
uint8_t temp = (*state)[0][1];
|
||||
(*state)[0][1] = (*state)[1][1];
|
||||
(*state)[1][1] = (*state)[2][1];
|
||||
(*state)[2][1] = (*state)[3][1];
|
||||
(*state)[3][1] = temp;
|
||||
|
||||
temp = (*state)[0][2];
|
||||
(*state)[0][2] = (*state)[2][2];
|
||||
(*state)[2][2] = temp;
|
||||
|
||||
temp = (*state)[1][2];
|
||||
(*state)[1][2] = (*state)[3][2];
|
||||
(*state)[3][2] = temp;
|
||||
|
||||
temp = (*state)[0][3];
|
||||
(*state)[0][3] = (*state)[3][3];
|
||||
(*state)[3][3] = (*state)[2][3];
|
||||
(*state)[2][3] = (*state)[1][3];
|
||||
(*state)[1][3] = temp;
|
||||
}
|
||||
|
||||
static uint8_t xtime(uint8_t x)
|
||||
{
|
||||
return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
|
||||
}
|
||||
|
||||
static void MixColumns(state_t *state)
|
||||
{
|
||||
for (uint8_t i = 0; i < 4; ++i) {
|
||||
uint8_t t = (*state)[i][0];
|
||||
uint8_t Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3];
|
||||
uint8_t Tm = (*state)[i][0] ^ (*state)[i][1];
|
||||
Tm = xtime(Tm);
|
||||
(*state)[i][0] ^= Tm ^ Tmp;
|
||||
Tm = (*state)[i][1] ^ (*state)[i][2];
|
||||
Tm = xtime(Tm);
|
||||
(*state)[i][1] ^= Tm ^ Tmp;
|
||||
Tm = (*state)[i][2] ^ (*state)[i][3];
|
||||
Tm = xtime(Tm);
|
||||
(*state)[i][2] ^= Tm ^ Tmp;
|
||||
Tm = (*state)[i][3] ^ t;
|
||||
Tm = xtime(Tm);
|
||||
(*state)[i][3] ^= Tm ^ Tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#define Multiply(x, y) \
|
||||
(((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ ((y >> 2 & 1) * xtime(xtime(x))) ^ ((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ \
|
||||
((y >> 4 & 1) * xtime(xtime(xtime(xtime(x))))))
|
||||
|
||||
static void Cipher(state_t *state, const uint8_t *RoundKey)
|
||||
{
|
||||
uint8_t round = 0;
|
||||
|
||||
AddRoundKey(0, state, RoundKey);
|
||||
|
||||
for (round = 1;; ++round) {
|
||||
SubBytes(state);
|
||||
ShiftRows(state);
|
||||
if (round == Nr) {
|
||||
break;
|
||||
}
|
||||
MixColumns(state);
|
||||
AddRoundKey(round, state, RoundKey);
|
||||
}
|
||||
AddRoundKey(Nr, state, RoundKey);
|
||||
}
|
||||
|
||||
void AES_CTR_xcrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, size_t length)
|
||||
{
|
||||
uint8_t buffer[AES_BLOCKLEN];
|
||||
|
||||
size_t i;
|
||||
int bi;
|
||||
for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) {
|
||||
if (bi == AES_BLOCKLEN) {
|
||||
|
||||
memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
|
||||
Cipher((state_t *)buffer, ctx->RoundKey);
|
||||
|
||||
for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) {
|
||||
if (ctx->Iv[bi] == 255) {
|
||||
ctx->Iv[bi] = 0;
|
||||
continue;
|
||||
}
|
||||
ctx->Iv[bi] += 1;
|
||||
break;
|
||||
}
|
||||
bi = 0;
|
||||
}
|
||||
|
||||
buf[i] = (buf[i] ^ buffer[bi]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
#define AES_keyExpSize 240
|
||||
|
||||
struct AES_ctx {
|
||||
uint8_t RoundKey[AES_keyExpSize];
|
||||
uint8_t Iv[AES_BLOCKLEN];
|
||||
uint8_t RoundKey[AES_keyExpSize];
|
||||
uint8_t Iv[AES_BLOCKLEN];
|
||||
};
|
||||
|
||||
void AES_init_ctx(struct AES_ctx *ctx, const uint8_t *key);
|
||||
|
||||
@@ -7,18 +7,26 @@
|
||||
* Custom new/delete to panic if out out memory
|
||||
*/
|
||||
|
||||
void *operator new(size_t size) {
|
||||
auto p = rtos_malloc(size);
|
||||
assert(p);
|
||||
return p;
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
auto p = rtos_malloc(size);
|
||||
assert(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *operator new[](size_t size) {
|
||||
auto p = rtos_malloc(size);
|
||||
assert(p);
|
||||
return p;
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
auto p = rtos_malloc(size);
|
||||
assert(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void operator delete(void *ptr) { rtos_free(ptr); }
|
||||
void operator delete(void *ptr)
|
||||
{
|
||||
rtos_free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void *ptr) { rtos_free(ptr); }
|
||||
void operator delete[](void *ptr)
|
||||
{
|
||||
rtos_free(ptr);
|
||||
}
|
||||
@@ -155,8 +155,8 @@
|
||||
// Debug printing to segger console
|
||||
#define SEGGER_MSG(...) SEGGER_RTT_printf(SEGGER_STDOUT_CH, __VA_ARGS__)
|
||||
|
||||
// If we are not on a NRF52840 (which has built in USB-ACM serial support) and we don't have serial pins hooked up, then
|
||||
// we MUST use SEGGER for debug output
|
||||
// If we are not on a NRF52840 (which has built in USB-ACM serial support) and we don't have serial pins hooked up, then we MUST
|
||||
// use SEGGER for debug output
|
||||
#if !defined(PIN_SERIAL_RX) && !defined(NRF52840_XXAA)
|
||||
// No serial ports on this board - ONLY use segger in memory console
|
||||
#define USE_SEGGER
|
||||
|
||||
@@ -1,90 +1,94 @@
|
||||
#include "configuration.h"
|
||||
#include <core_cm4.h>
|
||||
|
||||
// Based on reading/modifying
|
||||
// https://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/
|
||||
// Based on reading/modifying https://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/
|
||||
|
||||
enum { r0, r1, r2, r3, r12, lr, pc, psr };
|
||||
|
||||
// we can't use the regular LOG_DEBUG for these crash dumps because it depends on threading still being running. Instead
|
||||
// use the segger in memory tool
|
||||
// we can't use the regular LOG_DEBUG for these crash dumps because it depends on threading still being running. Instead use the
|
||||
// segger in memory tool
|
||||
#define FAULT_MSG(...) SEGGER_MSG(__VA_ARGS__)
|
||||
|
||||
// Per http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Cihcfefj.html
|
||||
static void printUsageErrorMsg(uint32_t cfsr) {
|
||||
FAULT_MSG("Usage fault: ");
|
||||
cfsr >>= SCB_CFSR_USGFAULTSR_Pos; // right shift to lsb
|
||||
if ((cfsr & (1 << 9)) != 0)
|
||||
FAULT_MSG("Divide by zero\n");
|
||||
else if ((cfsr & (1 << 8)) != 0)
|
||||
FAULT_MSG("Unaligned\n");
|
||||
else if ((cfsr & (1 << 1)) != 0)
|
||||
FAULT_MSG("Invalid state\n");
|
||||
else if ((cfsr & (1 << 0)) != 0)
|
||||
FAULT_MSG("Invalid instruction\n");
|
||||
else
|
||||
FAULT_MSG("FIXME add to printUsageErrorMsg!\n");
|
||||
static void printUsageErrorMsg(uint32_t cfsr)
|
||||
{
|
||||
FAULT_MSG("Usage fault: ");
|
||||
cfsr >>= SCB_CFSR_USGFAULTSR_Pos; // right shift to lsb
|
||||
if ((cfsr & (1 << 9)) != 0)
|
||||
FAULT_MSG("Divide by zero\n");
|
||||
else if ((cfsr & (1 << 8)) != 0)
|
||||
FAULT_MSG("Unaligned\n");
|
||||
else if ((cfsr & (1 << 1)) != 0)
|
||||
FAULT_MSG("Invalid state\n");
|
||||
else if ((cfsr & (1 << 0)) != 0)
|
||||
FAULT_MSG("Invalid instruction\n");
|
||||
else
|
||||
FAULT_MSG("FIXME add to printUsageErrorMsg!\n");
|
||||
}
|
||||
|
||||
static void printBusErrorMsg(uint32_t cfsr) {
|
||||
FAULT_MSG("Bus fault: ");
|
||||
cfsr >>= SCB_CFSR_BUSFAULTSR_Pos; // right shift to lsb
|
||||
if ((cfsr & (1 << 0)) != 0)
|
||||
FAULT_MSG("Instruction bus error\n");
|
||||
if ((cfsr & (1 << 1)) != 0)
|
||||
FAULT_MSG("Precise data bus error\n");
|
||||
if ((cfsr & (1 << 2)) != 0)
|
||||
FAULT_MSG("Imprecise data bus error\n");
|
||||
static void printBusErrorMsg(uint32_t cfsr)
|
||||
{
|
||||
FAULT_MSG("Bus fault: ");
|
||||
cfsr >>= SCB_CFSR_BUSFAULTSR_Pos; // right shift to lsb
|
||||
if ((cfsr & (1 << 0)) != 0)
|
||||
FAULT_MSG("Instruction bus error\n");
|
||||
if ((cfsr & (1 << 1)) != 0)
|
||||
FAULT_MSG("Precise data bus error\n");
|
||||
if ((cfsr & (1 << 2)) != 0)
|
||||
FAULT_MSG("Imprecise data bus error\n");
|
||||
}
|
||||
|
||||
static void printMemErrorMsg(uint32_t cfsr) {
|
||||
FAULT_MSG("Memory fault: ");
|
||||
cfsr >>= SCB_CFSR_MEMFAULTSR_Pos; // right shift to lsb
|
||||
if ((cfsr & (1 << 0)) != 0)
|
||||
FAULT_MSG("Instruction access violation\n");
|
||||
if ((cfsr & (1 << 1)) != 0)
|
||||
FAULT_MSG("Data access violation\n");
|
||||
static void printMemErrorMsg(uint32_t cfsr)
|
||||
{
|
||||
FAULT_MSG("Memory fault: ");
|
||||
cfsr >>= SCB_CFSR_MEMFAULTSR_Pos; // right shift to lsb
|
||||
if ((cfsr & (1 << 0)) != 0)
|
||||
FAULT_MSG("Instruction access violation\n");
|
||||
if ((cfsr & (1 << 1)) != 0)
|
||||
FAULT_MSG("Data access violation\n");
|
||||
}
|
||||
|
||||
extern "C" void HardFault_Impl(uint32_t stack[]) {
|
||||
FAULT_MSG("Hard Fault occurred! SCB->HFSR = 0x%08lx\n", SCB->HFSR);
|
||||
extern "C" void HardFault_Impl(uint32_t stack[])
|
||||
{
|
||||
FAULT_MSG("Hard Fault occurred! SCB->HFSR = 0x%08lx\n", SCB->HFSR);
|
||||
|
||||
if ((SCB->HFSR & SCB_HFSR_FORCED_Msk) != 0) {
|
||||
FAULT_MSG("Forced Hard Fault: SCB->CFSR = 0x%08lx\n", SCB->CFSR);
|
||||
if ((SCB->HFSR & SCB_HFSR_FORCED_Msk) != 0) {
|
||||
FAULT_MSG("Forced Hard Fault: SCB->CFSR = 0x%08lx\n", SCB->CFSR);
|
||||
|
||||
if ((SCB->CFSR & SCB_CFSR_USGFAULTSR_Msk) != 0) {
|
||||
printUsageErrorMsg(SCB->CFSR);
|
||||
}
|
||||
if ((SCB->CFSR & SCB_CFSR_BUSFAULTSR_Msk) != 0) {
|
||||
printBusErrorMsg(SCB->CFSR);
|
||||
}
|
||||
if ((SCB->CFSR & SCB_CFSR_MEMFAULTSR_Msk) != 0) {
|
||||
printMemErrorMsg(SCB->CFSR);
|
||||
if ((SCB->CFSR & SCB_CFSR_USGFAULTSR_Msk) != 0) {
|
||||
printUsageErrorMsg(SCB->CFSR);
|
||||
}
|
||||
if ((SCB->CFSR & SCB_CFSR_BUSFAULTSR_Msk) != 0) {
|
||||
printBusErrorMsg(SCB->CFSR);
|
||||
}
|
||||
if ((SCB->CFSR & SCB_CFSR_MEMFAULTSR_Msk) != 0) {
|
||||
printMemErrorMsg(SCB->CFSR);
|
||||
}
|
||||
|
||||
FAULT_MSG("r0 = 0x%08lx\n", stack[r0]);
|
||||
FAULT_MSG("r1 = 0x%08lx\n", stack[r1]);
|
||||
FAULT_MSG("r2 = 0x%08lx\n", stack[r2]);
|
||||
FAULT_MSG("r3 = 0x%08lx\n", stack[r3]);
|
||||
FAULT_MSG("r12 = 0x%08lx\n", stack[r12]);
|
||||
FAULT_MSG("lr = 0x%08lx\n", stack[lr]);
|
||||
FAULT_MSG("pc = 0x%08lx\n", stack[pc]);
|
||||
FAULT_MSG("psr = 0x%08lx\n", stack[psr]);
|
||||
}
|
||||
|
||||
FAULT_MSG("r0 = 0x%08lx\n", stack[r0]);
|
||||
FAULT_MSG("r1 = 0x%08lx\n", stack[r1]);
|
||||
FAULT_MSG("r2 = 0x%08lx\n", stack[r2]);
|
||||
FAULT_MSG("r3 = 0x%08lx\n", stack[r3]);
|
||||
FAULT_MSG("r12 = 0x%08lx\n", stack[r12]);
|
||||
FAULT_MSG("lr = 0x%08lx\n", stack[lr]);
|
||||
FAULT_MSG("pc = 0x%08lx\n", stack[pc]);
|
||||
FAULT_MSG("psr = 0x%08lx\n", stack[psr]);
|
||||
}
|
||||
FAULT_MSG("Done with fault report - Waiting to reboot\n");
|
||||
asm volatile("bkpt #01"); // Enter the debugger if one is connected
|
||||
|
||||
FAULT_MSG("Done with fault report - Waiting to reboot\n");
|
||||
asm volatile("bkpt #01"); // Enter the debugger if one is connected
|
||||
|
||||
// Don't spin, so that the debugger will let the user step to next instruction
|
||||
// while (1) ;
|
||||
// Don't spin, so that the debugger will let the user step to next instruction
|
||||
// while (1) ;
|
||||
}
|
||||
|
||||
#ifndef INC_FREERTOS_H
|
||||
// This is a generic cortex M entrypoint that doesn't assume freertos
|
||||
|
||||
extern "C" void HardFault_Handler(void) {
|
||||
asm volatile(" mrs r0,msp\n"
|
||||
" b HardFault_Impl \n");
|
||||
extern "C" void HardFault_Handler(void)
|
||||
{
|
||||
asm volatile(" mrs r0,msp\n"
|
||||
" b HardFault_Impl \n");
|
||||
}
|
||||
#elif !defined(ARCH_NRF52)
|
||||
|
||||
@@ -94,14 +98,15 @@ extern "C" void HardFault_Handler(void) __attribute__((naked));
|
||||
|
||||
/* The fault handler implementation calls a function called
|
||||
prvGetRegistersFromStack(). */
|
||||
extern "C" void HardFault_Handler(void) {
|
||||
__asm volatile(" tst lr, #4 \n"
|
||||
" ite eq \n"
|
||||
" mrseq r0, msp \n"
|
||||
" mrsne r0, psp \n"
|
||||
" ldr r1, [r0, #24] \n"
|
||||
" ldr r2, handler2_address_const \n"
|
||||
" bx r2 \n"
|
||||
" handler2_address_const: .word HardFault_Impl \n");
|
||||
extern "C" void HardFault_Handler(void)
|
||||
{
|
||||
__asm volatile(" tst lr, #4 \n"
|
||||
" ite eq \n"
|
||||
" mrseq r0, msp \n"
|
||||
" mrsne r0, psp \n"
|
||||
" ldr r1, [r0, #24] \n"
|
||||
" ldr r2, handler2_address_const \n"
|
||||
" bx r2 \n"
|
||||
" handler2_address_const: .word HardFault_Impl \n");
|
||||
}
|
||||
#endif
|
||||
|
||||
+317
-299
@@ -38,96 +38,101 @@ void variant_shutdown() {}
|
||||
static nrfx_wdt_t nrfx_wdt = NRFX_WDT_INSTANCE(0);
|
||||
static nrfx_wdt_channel_id nrfx_wdt_channel_id_nrf52_main;
|
||||
|
||||
static inline void debugger_break(void) {
|
||||
__asm volatile("bkpt #0x01\n\t"
|
||||
"mov pc, lr\n\t");
|
||||
static inline void debugger_break(void)
|
||||
{
|
||||
__asm volatile("bkpt #0x01\n\t"
|
||||
"mov pc, lr\n\t");
|
||||
}
|
||||
|
||||
bool loopCanSleep() {
|
||||
// turn off sleep only while connected via USB
|
||||
// return true;
|
||||
return !Serial; // the bool operator on the nrf52 serial class returns true if connected to a PC currently
|
||||
// return !(TinyUSBDevice.mounted() && !TinyUSBDevice.suspended());
|
||||
bool loopCanSleep()
|
||||
{
|
||||
// turn off sleep only while connected via USB
|
||||
// return true;
|
||||
return !Serial; // the bool operator on the nrf52 serial class returns true if connected to a PC currently
|
||||
// return !(TinyUSBDevice.mounted() && !TinyUSBDevice.suspended());
|
||||
}
|
||||
|
||||
// handle standard gcc assert failures
|
||||
void __attribute__((noreturn)) __assert_func(const char *file, int line, const char *func, const char *failedexpr) {
|
||||
LOG_ERROR("assert failed %s: %d, %s, test=%s", file, line, func, failedexpr);
|
||||
// debugger_break(); FIXME doesn't work, possibly not for segger
|
||||
// Reboot cpu
|
||||
NVIC_SystemReset();
|
||||
void __attribute__((noreturn)) __assert_func(const char *file, int line, const char *func, const char *failedexpr)
|
||||
{
|
||||
LOG_ERROR("assert failed %s: %d, %s, test=%s", file, line, func, failedexpr);
|
||||
// debugger_break(); FIXME doesn't work, possibly not for segger
|
||||
// Reboot cpu
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
void getMacAddr(uint8_t *dmac) {
|
||||
const uint8_t *src = (const uint8_t *)NRF_FICR->DEVICEADDR;
|
||||
dmac[5] = src[0];
|
||||
dmac[4] = src[1];
|
||||
dmac[3] = src[2];
|
||||
dmac[2] = src[3];
|
||||
dmac[1] = src[4];
|
||||
dmac[0] = src[5] | 0xc0; // MSB high two bits get set elsewhere in the bluetooth stack
|
||||
void getMacAddr(uint8_t *dmac)
|
||||
{
|
||||
const uint8_t *src = (const uint8_t *)NRF_FICR->DEVICEADDR;
|
||||
dmac[5] = src[0];
|
||||
dmac[4] = src[1];
|
||||
dmac[3] = src[2];
|
||||
dmac[2] = src[3];
|
||||
dmac[1] = src[4];
|
||||
dmac[0] = src[5] | 0xc0; // MSB high two bits get set elsewhere in the bluetooth stack
|
||||
}
|
||||
|
||||
static void initBrownout() {
|
||||
auto vccthresh = POWER_POFCON_THRESHOLD_V24;
|
||||
static void initBrownout()
|
||||
{
|
||||
auto vccthresh = POWER_POFCON_THRESHOLD_V24;
|
||||
|
||||
auto err_code = sd_power_pof_enable(POWER_POFCON_POF_Enabled);
|
||||
assert(err_code == NRF_SUCCESS);
|
||||
auto err_code = sd_power_pof_enable(POWER_POFCON_POF_Enabled);
|
||||
assert(err_code == NRF_SUCCESS);
|
||||
|
||||
err_code = sd_power_pof_threshold_set(vccthresh);
|
||||
assert(err_code == NRF_SUCCESS);
|
||||
err_code = sd_power_pof_threshold_set(vccthresh);
|
||||
assert(err_code == NRF_SUCCESS);
|
||||
|
||||
// We don't bother with setting up brownout if soft device is disabled - because during production we always use
|
||||
// softdevice
|
||||
// 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
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
void setBluetoothEnable(bool enable) {
|
||||
// For debugging use: don't use bluetooth
|
||||
if (!useSoftDevice) {
|
||||
if (enable)
|
||||
LOG_INFO("Disable NRF52 BLUETOOTH WHILE DEBUGGING");
|
||||
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;
|
||||
void setBluetoothEnable(bool enable)
|
||||
{
|
||||
// For debugging use: don't use bluetooth
|
||||
if (!useSoftDevice) {
|
||||
if (enable)
|
||||
LOG_INFO("Disable NRF52 BLUETOOTH WHILE DEBUGGING");
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
powerMon->setState(meshtastic_PowerMon_State_BT_On);
|
||||
|
||||
// If not yet set-up
|
||||
if (!nrf52Bluetooth) {
|
||||
LOG_DEBUG("Init NRF52 Bluetooth");
|
||||
nrf52Bluetooth = new NRF52Bluetooth();
|
||||
nrf52Bluetooth->setup();
|
||||
|
||||
// We delay brownout init until after BLE because BLE starts soft device
|
||||
initBrownout();
|
||||
// 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;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
powerMon->setState(meshtastic_PowerMon_State_BT_On);
|
||||
|
||||
// If not yet set-up
|
||||
if (!nrf52Bluetooth) {
|
||||
LOG_DEBUG("Init NRF52 Bluetooth");
|
||||
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) {
|
||||
powerMon->clearState(meshtastic_PowerMon_State_BT_On);
|
||||
nrf52Bluetooth->shutdown();
|
||||
}
|
||||
// Already setup, apparently
|
||||
else
|
||||
nrf52Bluetooth->resumeAdvertising();
|
||||
}
|
||||
// Disable (if previously set-up)
|
||||
else if (nrf52Bluetooth) {
|
||||
powerMon->clearState(meshtastic_PowerMon_State_BT_On);
|
||||
nrf52Bluetooth->shutdown();
|
||||
}
|
||||
}
|
||||
#else
|
||||
#warning NRF52 "Bluetooth disable" workaround does not apply to builds with MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
@@ -136,90 +141,97 @@ void setBluetoothEnable(bool enable) {}
|
||||
/**
|
||||
* Override printf to use the SEGGER output library (note - this does not effect the printf method on the debug console)
|
||||
*/
|
||||
int printf(const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
auto res = SEGGER_RTT_vprintf(0, fmt, &args);
|
||||
va_end(args);
|
||||
return res;
|
||||
int printf(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
auto res = SEGGER_RTT_vprintf(0, fmt, &args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
namespace {
|
||||
namespace
|
||||
{
|
||||
constexpr uint8_t NRF52_MAGIC_LFS_IS_CORRUPT = 0xF5;
|
||||
constexpr uint32_t MULTIPLE_CORRUPTION_DELAY_MILLIS = 20 * 60 * 1000;
|
||||
static unsigned long millis_until_formatting_again = 0;
|
||||
|
||||
// Report the critical error from loop(), giving a chance for the screen to be initialized first.
|
||||
inline void reportLittleFSCorruptionOnce() {
|
||||
static bool report_corruption = !!millis_until_formatting_again;
|
||||
if (report_corruption) {
|
||||
report_corruption = false;
|
||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_FLASH_CORRUPTION_UNRECOVERABLE);
|
||||
}
|
||||
inline void reportLittleFSCorruptionOnce()
|
||||
{
|
||||
static bool report_corruption = !!millis_until_formatting_again;
|
||||
if (report_corruption) {
|
||||
report_corruption = false;
|
||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_FLASH_CORRUPTION_UNRECOVERABLE);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void preFSBegin() {
|
||||
// The GPREGRET register keeps its value across warm boots. Check that this is a warm boot and, if GPREGRET
|
||||
// is set to NRF52_MAGIC_LFS_IS_CORRUPT, format LittleFS.
|
||||
if (!(NRF_POWER->RESETREAS == 0 && NRF_POWER->GPREGRET == NRF52_MAGIC_LFS_IS_CORRUPT))
|
||||
return;
|
||||
NRF_POWER->GPREGRET = 0;
|
||||
millis_until_formatting_again = millis() + MULTIPLE_CORRUPTION_DELAY_MILLIS;
|
||||
InternalFS.format();
|
||||
LOG_INFO("LittleFS format complete; restoring default settings");
|
||||
void preFSBegin()
|
||||
{
|
||||
// The GPREGRET register keeps its value across warm boots. Check that this is a warm boot and, if GPREGRET
|
||||
// is set to NRF52_MAGIC_LFS_IS_CORRUPT, format LittleFS.
|
||||
if (!(NRF_POWER->RESETREAS == 0 && NRF_POWER->GPREGRET == NRF52_MAGIC_LFS_IS_CORRUPT))
|
||||
return;
|
||||
NRF_POWER->GPREGRET = 0;
|
||||
millis_until_formatting_again = millis() + MULTIPLE_CORRUPTION_DELAY_MILLIS;
|
||||
InternalFS.format();
|
||||
LOG_INFO("LittleFS format complete; restoring default settings");
|
||||
}
|
||||
|
||||
extern "C" void lfs_assert(const char *reason) {
|
||||
LOG_ERROR("LittleFS corruption detected: %s", reason);
|
||||
if (millis_until_formatting_again > millis()) {
|
||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_FLASH_CORRUPTION_UNRECOVERABLE);
|
||||
const long millis_remain = millis_until_formatting_again - millis();
|
||||
LOG_WARN("Pausing %d seconds to avoid wear on flash storage", millis_remain / 1000);
|
||||
delay(millis_remain);
|
||||
}
|
||||
LOG_INFO("Rebooting to format LittleFS");
|
||||
delay(500); // Give the serial port a bit of time to output that last message.
|
||||
// Try setting GPREGRET with the SoftDevice first. If that fails (perhaps because the SD hasn't been initialize yet)
|
||||
// then set NRF_POWER->GPREGRET directly.
|
||||
if (!(sd_power_gpregret_clr(0, 0xFF) == NRF_SUCCESS && sd_power_gpregret_set(0, NRF52_MAGIC_LFS_IS_CORRUPT) == NRF_SUCCESS)) {
|
||||
NRF_POWER->GPREGRET = NRF52_MAGIC_LFS_IS_CORRUPT;
|
||||
}
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
void checkSDEvents() {
|
||||
if (useSoftDevice) {
|
||||
uint32_t evt;
|
||||
while (NRF_SUCCESS == sd_evt_get(&evt)) {
|
||||
switch (evt) {
|
||||
case NRF_EVT_POWER_FAILURE_WARNING:
|
||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_BROWNOUT);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_DEBUG("Unexpected SDevt %d", evt);
|
||||
break;
|
||||
}
|
||||
extern "C" void lfs_assert(const char *reason)
|
||||
{
|
||||
LOG_ERROR("LittleFS corruption detected: %s", reason);
|
||||
if (millis_until_formatting_again > millis()) {
|
||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_FLASH_CORRUPTION_UNRECOVERABLE);
|
||||
const long millis_remain = millis_until_formatting_again - millis();
|
||||
LOG_WARN("Pausing %d seconds to avoid wear on flash storage", millis_remain / 1000);
|
||||
delay(millis_remain);
|
||||
}
|
||||
} else {
|
||||
if (NRF_POWER->EVENTS_POFWARN)
|
||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_BROWNOUT);
|
||||
}
|
||||
LOG_INFO("Rebooting to format LittleFS");
|
||||
delay(500); // Give the serial port a bit of time to output that last message.
|
||||
// Try setting GPREGRET with the SoftDevice first. If that fails (perhaps because the SD hasn't been initialize yet) then set
|
||||
// NRF_POWER->GPREGRET directly.
|
||||
if (!(sd_power_gpregret_clr(0, 0xFF) == NRF_SUCCESS && sd_power_gpregret_set(0, NRF52_MAGIC_LFS_IS_CORRUPT) == NRF_SUCCESS)) {
|
||||
NRF_POWER->GPREGRET = NRF52_MAGIC_LFS_IS_CORRUPT;
|
||||
}
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
void nrf52Loop() {
|
||||
{
|
||||
static bool watchdog_running = false;
|
||||
if (!watchdog_running) {
|
||||
nrfx_wdt_enable(&nrfx_wdt);
|
||||
watchdog_running = true;
|
||||
}
|
||||
}
|
||||
nrfx_wdt_channel_feed(&nrfx_wdt, nrfx_wdt_channel_id_nrf52_main);
|
||||
void checkSDEvents()
|
||||
{
|
||||
if (useSoftDevice) {
|
||||
uint32_t evt;
|
||||
while (NRF_SUCCESS == sd_evt_get(&evt)) {
|
||||
switch (evt) {
|
||||
case NRF_EVT_POWER_FAILURE_WARNING:
|
||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_BROWNOUT);
|
||||
break;
|
||||
|
||||
checkSDEvents();
|
||||
reportLittleFSCorruptionOnce();
|
||||
default:
|
||||
LOG_DEBUG("Unexpected SDevt %d", evt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (NRF_POWER->EVENTS_POFWARN)
|
||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_BROWNOUT);
|
||||
}
|
||||
}
|
||||
|
||||
void nrf52Loop()
|
||||
{
|
||||
{
|
||||
static bool watchdog_running = false;
|
||||
if (!watchdog_running) {
|
||||
nrfx_wdt_enable(&nrfx_wdt);
|
||||
watchdog_running = true;
|
||||
}
|
||||
}
|
||||
nrfx_wdt_channel_feed(&nrfx_wdt, nrfx_wdt_channel_id_nrf52_main);
|
||||
|
||||
checkSDEvents();
|
||||
reportLittleFSCorruptionOnce();
|
||||
}
|
||||
|
||||
#ifdef USE_SEMIHOSTING
|
||||
@@ -235,243 +247,249 @@ 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);
|
||||
}
|
||||
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() {
|
||||
void nrf52Setup()
|
||||
{
|
||||
#ifdef ADC_V
|
||||
pinMode(ADC_V, INPUT);
|
||||
pinMode(ADC_V, INPUT);
|
||||
#endif
|
||||
|
||||
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", why);
|
||||
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", why);
|
||||
|
||||
#ifdef USE_SEMIHOSTING
|
||||
nrf52InitSemiHosting();
|
||||
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
|
||||
NVIC_SetPriority(DebugMonitor_IRQn, 6UL);
|
||||
// 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
|
||||
NVIC_SetPriority(DebugMonitor_IRQn, 6UL);
|
||||
|
||||
#ifdef BQ25703A_ADDR
|
||||
auto *bq = new BQ25713();
|
||||
if (!bq->setup())
|
||||
LOG_ERROR("ERROR! Charge controller init failed");
|
||||
auto *bq = new BQ25713();
|
||||
if (!bq->setup())
|
||||
LOG_ERROR("ERROR! Charge controller init failed");
|
||||
#endif
|
||||
|
||||
// Init random seed
|
||||
union seedParts {
|
||||
uint32_t seed32;
|
||||
uint8_t seed8[4];
|
||||
} seed;
|
||||
nRFCrypto.begin();
|
||||
nRFCrypto.Random.generate(seed.seed8, sizeof(seed.seed8));
|
||||
LOG_DEBUG("Set random seed %u", seed.seed32);
|
||||
randomSeed(seed.seed32);
|
||||
nRFCrypto.end();
|
||||
// Init random seed
|
||||
union seedParts {
|
||||
uint32_t seed32;
|
||||
uint8_t seed8[4];
|
||||
} seed;
|
||||
nRFCrypto.begin();
|
||||
nRFCrypto.Random.generate(seed.seed8, sizeof(seed.seed8));
|
||||
LOG_DEBUG("Set random seed %u", seed.seed32);
|
||||
randomSeed(seed.seed32);
|
||||
nRFCrypto.end();
|
||||
|
||||
// Set up nrfx watchdog. Do not enable the watchdog yet (we do that
|
||||
// the first time through the main loop), so that other threads can
|
||||
// allocate their own wdt channel to protect themselves from hangs.
|
||||
nrfx_wdt_config_t wdt0_config = {
|
||||
.behaviour = NRF_WDT_BEHAVIOUR_PAUSE_SLEEP_HALT, .reload_value = APP_WATCHDOG_SECS * 1000,
|
||||
// Note: Not using wdt interrupts.
|
||||
// .interrupt_priority = NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY
|
||||
};
|
||||
nrfx_err_t r = nrfx_wdt_init(&nrfx_wdt, &wdt0_config,
|
||||
nullptr // Watchdog event handler, not used, we just reset.
|
||||
);
|
||||
assert(r == NRFX_SUCCESS);
|
||||
// Set up nrfx watchdog. Do not enable the watchdog yet (we do that
|
||||
// the first time through the main loop), so that other threads can
|
||||
// allocate their own wdt channel to protect themselves from hangs.
|
||||
nrfx_wdt_config_t wdt0_config = {
|
||||
.behaviour = NRF_WDT_BEHAVIOUR_PAUSE_SLEEP_HALT, .reload_value = APP_WATCHDOG_SECS * 1000,
|
||||
// Note: Not using wdt interrupts.
|
||||
// .interrupt_priority = NRFX_WDT_DEFAULT_CONFIG_IRQ_PRIORITY
|
||||
};
|
||||
nrfx_err_t r = nrfx_wdt_init(&nrfx_wdt, &wdt0_config,
|
||||
nullptr // Watchdog event handler, not used, we just reset.
|
||||
);
|
||||
assert(r == NRFX_SUCCESS);
|
||||
|
||||
r = nrfx_wdt_channel_alloc(&nrfx_wdt, &nrfx_wdt_channel_id_nrf52_main);
|
||||
assert(r == NRFX_SUCCESS);
|
||||
r = nrfx_wdt_channel_alloc(&nrfx_wdt, &nrfx_wdt_channel_id_nrf52_main);
|
||||
assert(r == NRFX_SUCCESS);
|
||||
}
|
||||
|
||||
void cpuDeepSleep(uint32_t msecToWake) {
|
||||
// FIXME, configure RTC or button press to wake us
|
||||
// FIXME, power down SPI, I2C, RAMs
|
||||
void cpuDeepSleep(uint32_t msecToWake)
|
||||
{
|
||||
// FIXME, configure RTC or button press to wake us
|
||||
// FIXME, power down SPI, I2C, RAMs
|
||||
#if HAS_WIRE
|
||||
Wire.end();
|
||||
Wire.end();
|
||||
#endif
|
||||
SPI.end();
|
||||
SPI.end();
|
||||
#if SPI_INTERFACES_COUNT > 1
|
||||
SPI1.end();
|
||||
SPI1.end();
|
||||
#endif
|
||||
if (Serial) // Another check in case of disabled default serial, does nothing bad
|
||||
Serial.end(); // This may cause crashes as debug messages continue to flow.
|
||||
if (Serial) // Another check in case of disabled default serial, does nothing bad
|
||||
Serial.end(); // This may cause crashes as debug messages continue to flow.
|
||||
|
||||
// This causes troubles with waking up on nrf52 (on pro-micro in particular):
|
||||
// we have no Serial1 in use on nrf52, check Serial and GPS modules.
|
||||
// This causes troubles with waking up on nrf52 (on pro-micro in particular):
|
||||
// we have no Serial1 in use on nrf52, check Serial and GPS modules.
|
||||
#ifdef PIN_SERIAL1_RX
|
||||
if (Serial1) // A straightforward solution to the wake from deepsleep problem
|
||||
Serial1.end();
|
||||
if (Serial1) // A straightforward solution to the wake from deepsleep problem
|
||||
Serial1.end();
|
||||
#endif
|
||||
|
||||
#ifdef TTGO_T_ECHO
|
||||
// To power off the T-Echo, the display must be set
|
||||
// as an input pin; otherwise, there will be leakage current.
|
||||
pinMode(PIN_EINK_CS, INPUT);
|
||||
pinMode(PIN_EINK_DC, INPUT);
|
||||
pinMode(PIN_EINK_RES, INPUT);
|
||||
pinMode(PIN_EINK_BUSY, INPUT);
|
||||
// To power off the T-Echo, the display must be set
|
||||
// as an input pin; otherwise, there will be leakage current.
|
||||
pinMode(PIN_EINK_CS, INPUT);
|
||||
pinMode(PIN_EINK_DC, INPUT);
|
||||
pinMode(PIN_EINK_RES, INPUT);
|
||||
pinMode(PIN_EINK_BUSY, INPUT);
|
||||
#endif
|
||||
|
||||
setBluetoothEnable(false);
|
||||
setBluetoothEnable(false);
|
||||
|
||||
#ifdef RAK4630
|
||||
#ifdef PIN_3V3_EN
|
||||
digitalWrite(PIN_3V3_EN, LOW);
|
||||
digitalWrite(PIN_3V3_EN, LOW);
|
||||
#endif
|
||||
#ifdef AQ_SET_PIN
|
||||
// RAK-12039 set pin for Air quality sensor
|
||||
digitalWrite(AQ_SET_PIN, LOW);
|
||||
// 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);
|
||||
// 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);
|
||||
|
||||
// nrf_gpio_cfg_default(WB_I2C2_SCL);
|
||||
// nrf_gpio_cfg_default(WB_I2C2_SDA);
|
||||
// nrf_gpio_cfg_default(WB_I2C2_SCL);
|
||||
// nrf_gpio_cfg_default(WB_I2C2_SDA);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MESHLINK
|
||||
#ifdef PIN_WD_EN
|
||||
digitalWrite(PIN_WD_EN, LOW);
|
||||
digitalWrite(PIN_WD_EN, LOW);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_MESH_SOLAR)
|
||||
nrf_gpio_cfg_default(PIN_GPS_PPS);
|
||||
detachInterrupt(PIN_GPS_PPS);
|
||||
detachInterrupt(PIN_BUTTON1);
|
||||
nrf_gpio_cfg_default(PIN_GPS_PPS);
|
||||
detachInterrupt(PIN_GPS_PPS);
|
||||
detachInterrupt(PIN_BUTTON1);
|
||||
#endif
|
||||
|
||||
#ifdef ELECROW_ThinkNode_M1
|
||||
for (int pin = 0; pin < 48; pin++) {
|
||||
if (pin == 17 || pin == 19 || pin == 20 || pin == 22 || pin == 23 || pin == 24 || pin == 25 || pin == 9 || pin == 10 || pin == PIN_BUTTON1 ||
|
||||
pin == PIN_BUTTON2) {
|
||||
continue;
|
||||
for (int pin = 0; pin < 48; pin++) {
|
||||
if (pin == 17 || pin == 19 || pin == 20 || pin == 22 || pin == 23 || pin == 24 || pin == 25 || pin == 9 || pin == 10 ||
|
||||
pin == PIN_BUTTON1 || pin == PIN_BUTTON2) {
|
||||
continue;
|
||||
}
|
||||
pinMode(pin, OUTPUT);
|
||||
}
|
||||
pinMode(pin, OUTPUT);
|
||||
}
|
||||
for (int pin = 0; pin < 48; pin++) {
|
||||
if (pin == 17 || pin == 19 || pin == 20 || pin == 22 || pin == 23 || pin == 24 || pin == 25 || pin == 9 || pin == 10 || pin == PIN_BUTTON1 ||
|
||||
pin == PIN_BUTTON2) {
|
||||
continue;
|
||||
for (int pin = 0; pin < 48; pin++) {
|
||||
if (pin == 17 || pin == 19 || pin == 20 || pin == 22 || pin == 23 || pin == 24 || pin == 25 || pin == 9 || pin == 10 ||
|
||||
pin == PIN_BUTTON1 || pin == PIN_BUTTON2) {
|
||||
continue;
|
||||
}
|
||||
digitalWrite(pin, LOW);
|
||||
}
|
||||
digitalWrite(pin, LOW);
|
||||
}
|
||||
for (int pin = 0; pin < 48; pin++) {
|
||||
if (pin == 17 || pin == 19 || pin == 20 || pin == 22 || pin == 23 || pin == 24 || pin == 25 || pin == 9 || pin == 10 || pin == PIN_BUTTON1 ||
|
||||
pin == PIN_BUTTON2) {
|
||||
continue;
|
||||
for (int pin = 0; pin < 48; pin++) {
|
||||
if (pin == 17 || pin == 19 || pin == 20 || pin == 22 || pin == 23 || pin == 24 || pin == 25 || pin == 9 || pin == 10 ||
|
||||
pin == PIN_BUTTON1 || pin == PIN_BUTTON2) {
|
||||
continue;
|
||||
}
|
||||
NRF_GPIO->DIRCLR = (1 << pin);
|
||||
}
|
||||
NRF_GPIO->DIRCLR = (1 << pin);
|
||||
}
|
||||
#endif
|
||||
variant_shutdown();
|
||||
variant_shutdown();
|
||||
|
||||
// Sleepy trackers or sensors can low power "sleep"
|
||||
// Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event
|
||||
if (msecToWake != portMAX_DELAY && (IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TRACKER,
|
||||
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER, meshtastic_Config_DeviceConfig_Role_SENSOR) &&
|
||||
config.power.is_power_saving == true)) {
|
||||
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
|
||||
delay(msecToWake);
|
||||
NVIC_SystemReset();
|
||||
} else {
|
||||
// Resume on user button press
|
||||
// https://github.com/lyusupov/SoftRF/blob/81c519ca75693b696752235d559e881f2e0511ee/software/firmware/source/SoftRF/src/platform/nRF52.cpp#L1738
|
||||
constexpr uint32_t DFU_MAGIC_SKIP = 0x6d;
|
||||
sd_power_gpregret_clr(0, 0xFF); // Clear the register before setting a new values in it for stability reasons
|
||||
sd_power_gpregret_set(0, DFU_MAGIC_SKIP); // Equivalent NRF_POWER->GPREGRET = DFU_MAGIC_SKIP
|
||||
// Sleepy trackers or sensors can low power "sleep"
|
||||
// Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event
|
||||
if (msecToWake != portMAX_DELAY &&
|
||||
(IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TRACKER,
|
||||
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER, meshtastic_Config_DeviceConfig_Role_SENSOR) &&
|
||||
config.power.is_power_saving == true)) {
|
||||
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
|
||||
delay(msecToWake);
|
||||
NVIC_SystemReset();
|
||||
} else {
|
||||
// Resume on user button press
|
||||
// https://github.com/lyusupov/SoftRF/blob/81c519ca75693b696752235d559e881f2e0511ee/software/firmware/source/SoftRF/src/platform/nRF52.cpp#L1738
|
||||
constexpr uint32_t DFU_MAGIC_SKIP = 0x6d;
|
||||
sd_power_gpregret_clr(0, 0xFF); // Clear the register before setting a new values in it for stability reasons
|
||||
sd_power_gpregret_set(0, DFU_MAGIC_SKIP); // Equivalent NRF_POWER->GPREGRET = DFU_MAGIC_SKIP
|
||||
|
||||
// FIXME, use system off mode with ram retention for key state?
|
||||
// FIXME, use non-init RAM per
|
||||
// https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled
|
||||
// FIXME, use system off mode with ram retention for key state?
|
||||
// FIXME, use non-init RAM per
|
||||
// https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled
|
||||
|
||||
#ifdef ELECROW_ThinkNode_M1
|
||||
nrf_gpio_cfg_input(PIN_BUTTON1, NRF_GPIO_PIN_PULLUP); // Configure the pin to be woken up as an input
|
||||
nrf_gpio_pin_sense_t sense = NRF_GPIO_PIN_SENSE_LOW;
|
||||
nrf_gpio_cfg_sense_set(PIN_BUTTON1, sense);
|
||||
nrf_gpio_cfg_input(PIN_BUTTON1, NRF_GPIO_PIN_PULLUP); // Configure the pin to be woken up as an input
|
||||
nrf_gpio_pin_sense_t sense = NRF_GPIO_PIN_SENSE_LOW;
|
||||
nrf_gpio_cfg_sense_set(PIN_BUTTON1, sense);
|
||||
|
||||
nrf_gpio_cfg_input(PIN_BUTTON2, NRF_GPIO_PIN_PULLUP);
|
||||
nrf_gpio_pin_sense_t sense1 = NRF_GPIO_PIN_SENSE_LOW;
|
||||
nrf_gpio_cfg_sense_set(PIN_BUTTON2, sense1);
|
||||
nrf_gpio_cfg_input(PIN_BUTTON2, NRF_GPIO_PIN_PULLUP);
|
||||
nrf_gpio_pin_sense_t sense1 = NRF_GPIO_PIN_SENSE_LOW;
|
||||
nrf_gpio_cfg_sense_set(PIN_BUTTON2, sense1);
|
||||
#endif
|
||||
|
||||
#ifdef PROMICRO_DIY_TCXO
|
||||
nrf_gpio_cfg_input(BUTTON_PIN, NRF_GPIO_PIN_PULLUP); // Enable internal pull-up on the button pin
|
||||
nrf_gpio_pin_sense_t sense = NRF_GPIO_PIN_SENSE_LOW; // Configure SENSE signal on low edge
|
||||
nrf_gpio_cfg_sense_set(BUTTON_PIN, sense); // Apply SENSE to wake up the device from the deep sleep
|
||||
nrf_gpio_cfg_input(BUTTON_PIN, NRF_GPIO_PIN_PULLUP); // Enable internal pull-up on the button pin
|
||||
nrf_gpio_pin_sense_t sense = NRF_GPIO_PIN_SENSE_LOW; // Configure SENSE signal on low edge
|
||||
nrf_gpio_cfg_sense_set(BUTTON_PIN, sense); // Apply SENSE to wake up the device from the deep sleep
|
||||
#endif
|
||||
|
||||
#ifdef BATTERY_LPCOMP_INPUT
|
||||
// Wake up if power rises again
|
||||
nrf_lpcomp_config_t c;
|
||||
c.reference = BATTERY_LPCOMP_THRESHOLD;
|
||||
c.detection = NRF_LPCOMP_DETECT_UP;
|
||||
c.hyst = NRF_LPCOMP_HYST_NOHYST;
|
||||
nrf_lpcomp_configure(NRF_LPCOMP, &c);
|
||||
nrf_lpcomp_input_select(NRF_LPCOMP, BATTERY_LPCOMP_INPUT);
|
||||
nrf_lpcomp_enable(NRF_LPCOMP);
|
||||
// Wake up if power rises again
|
||||
nrf_lpcomp_config_t c;
|
||||
c.reference = BATTERY_LPCOMP_THRESHOLD;
|
||||
c.detection = NRF_LPCOMP_DETECT_UP;
|
||||
c.hyst = NRF_LPCOMP_HYST_NOHYST;
|
||||
nrf_lpcomp_configure(NRF_LPCOMP, &c);
|
||||
nrf_lpcomp_input_select(NRF_LPCOMP, BATTERY_LPCOMP_INPUT);
|
||||
nrf_lpcomp_enable(NRF_LPCOMP);
|
||||
|
||||
battery_adcEnable();
|
||||
battery_adcEnable();
|
||||
|
||||
nrf_lpcomp_task_trigger(NRF_LPCOMP, NRF_LPCOMP_TASK_START);
|
||||
while (!nrf_lpcomp_event_check(NRF_LPCOMP, NRF_LPCOMP_EVENT_READY))
|
||||
;
|
||||
nrf_lpcomp_task_trigger(NRF_LPCOMP, NRF_LPCOMP_TASK_START);
|
||||
while (!nrf_lpcomp_event_check(NRF_LPCOMP, NRF_LPCOMP_EVENT_READY))
|
||||
;
|
||||
#endif
|
||||
|
||||
auto ok = sd_power_system_off();
|
||||
if (ok != NRF_SUCCESS) {
|
||||
LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!");
|
||||
NRF_POWER->SYSTEMOFF = 1;
|
||||
auto ok = sd_power_system_off();
|
||||
if (ok != NRF_SUCCESS) {
|
||||
LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!");
|
||||
NRF_POWER->SYSTEMOFF = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The following code should not be run, because we are off
|
||||
while (1) {
|
||||
delay(5000);
|
||||
LOG_DEBUG(".");
|
||||
}
|
||||
// The following code should not be run, because we are off
|
||||
while (1) {
|
||||
delay(5000);
|
||||
LOG_DEBUG(".");
|
||||
}
|
||||
}
|
||||
|
||||
void clearBonds() {
|
||||
if (!nrf52Bluetooth) {
|
||||
nrf52Bluetooth = new NRF52Bluetooth();
|
||||
nrf52Bluetooth->setup();
|
||||
}
|
||||
nrf52Bluetooth->clearBonds();
|
||||
void clearBonds()
|
||||
{
|
||||
if (!nrf52Bluetooth) {
|
||||
nrf52Bluetooth = new NRF52Bluetooth();
|
||||
nrf52Bluetooth->setup();
|
||||
}
|
||||
nrf52Bluetooth->clearBonds();
|
||||
}
|
||||
|
||||
void enterDfuMode() {
|
||||
void enterDfuMode()
|
||||
{
|
||||
// SDK kit does not have native USB like almost all other NRF52 boards
|
||||
#ifdef NRF_USE_SERIAL_DFU
|
||||
enterSerialDfu();
|
||||
enterSerialDfu();
|
||||
#else
|
||||
enterUf2Dfu();
|
||||
enterUf2Dfu();
|
||||
#endif
|
||||
}
|
||||
|
||||
+117
-124
@@ -70,26 +70,26 @@ extern "C" {
|
||||
* @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. */
|
||||
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 */
|
||||
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.
|
||||
@@ -97,11 +97,11 @@ enum BLE_COMMON_EVTS {
|
||||
* 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. */
|
||||
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.
|
||||
@@ -109,16 +109,16 @@ enum BLE_CONN_CFGS {
|
||||
* IDs that uniquely identify a common configuration.
|
||||
*/
|
||||
enum BLE_COMMON_CFGS {
|
||||
BLE_COMMON_CFG_VS_UUID = BLE_CFG_BASE, /**< Vendor specific base UUID configuration */
|
||||
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 */
|
||||
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 */
|
||||
};
|
||||
|
||||
/** @} */
|
||||
@@ -136,11 +136,10 @@ enum BLE_COMMON_OPTS {
|
||||
|
||||
/** @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.
|
||||
* 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))
|
||||
#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
|
||||
* @{ */
|
||||
@@ -169,68 +168,67 @@ enum BLE_COMMON_OPTS {
|
||||
|
||||
/**@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. */
|
||||
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. */
|
||||
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 */
|
||||
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. */
|
||||
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_<module>_EVT series. */
|
||||
uint16_t evt_len; /**< Length in octets including this header. */
|
||||
uint16_t evt_id; /**< Value from a BLE_<module>_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_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). */
|
||||
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 */
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -243,16 +241,16 @@ typedef struct {
|
||||
* 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.
|
||||
* @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 */
|
||||
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 */
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -260,27 +258,25 @@ typedef struct {
|
||||
*
|
||||
* 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.
|
||||
* 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. */
|
||||
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 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().
|
||||
@@ -288,29 +284,28 @@ typedef struct {
|
||||
* @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. */
|
||||
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_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_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,
|
||||
* 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.
|
||||
@@ -324,18 +319,17 @@ typedef union {
|
||||
|
||||
*/
|
||||
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. */
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -344,22 +338,22 @@ typedef struct {
|
||||
* @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. */
|
||||
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_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_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;
|
||||
|
||||
/** @} */
|
||||
@@ -408,12 +402,11 @@ typedef union {
|
||||
* @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.
|
||||
* 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.
|
||||
* @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));
|
||||
|
||||
@@ -468,12 +461,11 @@ SVCALL(SD_BLE_CFG_SET, uint32_t, sd_ble_cfg_set(uint32_t cfg_id, ble_cfg_t const
|
||||
* 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,
|
||||
* 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:
|
||||
* 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;
|
||||
@@ -512,8 +504,8 @@ SVCALL(SD_BLE_EVT_GET, uint32_t, sd_ble_evt_get(uint8_t *p_dest, uint16_t *p_len
|
||||
*
|
||||
* @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.
|
||||
* @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.
|
||||
@@ -526,13 +518,14 @@ SVCALL(SD_BLE_UUID_VS_ADD, uint32_t, sd_ble_uuid_vs_add(ble_uuid128_t const *p_v
|
||||
* @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.
|
||||
* @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.
|
||||
* @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.
|
||||
@@ -563,8 +556,8 @@ SVCALL(SD_BLE_UUID_DECODE, uint32_t, sd_ble_uuid_decode(uint8_t uuid_le_len, uin
|
||||
|
||||
/** @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.
|
||||
* @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).
|
||||
|
||||
@@ -67,8 +67,8 @@ extern "C" {
|
||||
#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. */
|
||||
#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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -112,34 +112,34 @@ extern "C" {
|
||||
#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_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. */
|
||||
#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
|
||||
@@ -194,32 +194,32 @@ extern "C" {
|
||||
* @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
|
||||
*/
|
||||
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. */
|
||||
/* 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. */
|
||||
/* 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;
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -63,56 +63,53 @@ extern "C" {
|
||||
|
||||
/**@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. */
|
||||
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. */
|
||||
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 */
|
||||
BLE_GATTC_OPT_UUID_DISC = BLE_GATTC_OPT_BASE, /**< UUID discovery. @ref ble_gattc_opt_uuid_disc_t */
|
||||
};
|
||||
|
||||
/** @} */
|
||||
@@ -133,7 +130,8 @@ enum BLE_GATTC_OPTS {
|
||||
|
||||
/** @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. */
|
||||
#define BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT \
|
||||
1 /**< Default number of Write without Response that can be queued for transmission. */
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
||||
@@ -145,206 +143,208 @@ enum BLE_GATTC_OPTS {
|
||||
* @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 */
|
||||
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. */
|
||||
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_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. */
|
||||
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_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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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.
|
||||
@@ -370,13 +370,12 @@ typedef struct {
|
||||
*
|
||||
*/
|
||||
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. */
|
||||
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_uuid_disc_t uuid_disc; /**< Parameters for the UUID discovery option. */
|
||||
} ble_gattc_opt_t;
|
||||
|
||||
/** @} */
|
||||
@@ -387,8 +386,8 @@ typedef union {
|
||||
/**@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.
|
||||
* 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}
|
||||
@@ -415,8 +414,8 @@ SVCALL(SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER, uint32_t,
|
||||
|
||||
/**@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
|
||||
* @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
|
||||
@@ -444,8 +443,8 @@ SVCALL(SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, uint32_t,
|
||||
|
||||
/**@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
|
||||
* @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
|
||||
@@ -472,8 +471,8 @@ SVCALL(SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, uint32_t,
|
||||
|
||||
/**@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
|
||||
* @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
|
||||
@@ -500,8 +499,8 @@ SVCALL(SD_BLE_GATTC_DESCRIPTORS_DISCOVER, uint32_t,
|
||||
|
||||
/**@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.
|
||||
* @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}
|
||||
@@ -524,13 +523,14 @@ SVCALL(SD_BLE_GATTC_DESCRIPTORS_DISCOVER, uint32_t,
|
||||
* 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));
|
||||
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.
|
||||
* @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}
|
||||
@@ -580,8 +580,8 @@ SVCALL(SD_BLE_GATTC_READ, uint32_t, sd_ble_gattc_read(uint16_t conn_handle, uint
|
||||
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.
|
||||
/**@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.
|
||||
*
|
||||
@@ -591,17 +591,17 @@ SVCALL(SD_BLE_GATTC_CHAR_VALUES_READ, uint32_t,
|
||||
* 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.
|
||||
* 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:
|
||||
* @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.
|
||||
* - 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.}
|
||||
@@ -624,8 +624,8 @@ SVCALL(SD_BLE_GATTC_CHAR_VALUES_READ, uint32_t,
|
||||
* @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_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
|
||||
@@ -654,8 +654,7 @@ SVCALL(SD_BLE_GATTC_HV_CONFIRM, uint32_t, sd_ble_gattc_hv_confirm(uint16_t conn_
|
||||
/**@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.}
|
||||
* @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.
|
||||
@@ -693,8 +692,7 @@ SVCALL(SD_BLE_GATTC_ATTR_INFO_DISCOVER, uint32_t,
|
||||
* - 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
|
||||
* - 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.
|
||||
@@ -705,7 +703,8 @@ SVCALL(SD_BLE_GATTC_ATTR_INFO_DISCOVER, uint32_t,
|
||||
* @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));
|
||||
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.
|
||||
*
|
||||
@@ -730,24 +729,27 @@ SVCALL(SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, uint32_t, sd_ble_gattc_exchange_mtu_re
|
||||
* @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);
|
||||
__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;
|
||||
__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;
|
||||
}
|
||||
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 */
|
||||
|
||||
@@ -66,51 +66,45 @@ extern "C" {
|
||||
* @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. */
|
||||
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. */
|
||||
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.
|
||||
@@ -118,9 +112,9 @@ enum BLE_GATTS_EVTS {
|
||||
* 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. */
|
||||
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. */
|
||||
};
|
||||
|
||||
/** @} */
|
||||
@@ -174,10 +168,10 @@ enum BLE_GATTS_CFGS {
|
||||
* @{ */
|
||||
#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. */
|
||||
#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
|
||||
@@ -196,7 +190,8 @@ enum BLE_GATTS_CFGS {
|
||||
/** @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. */
|
||||
#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
|
||||
@@ -209,7 +204,8 @@ enum BLE_GATTS_CFGS {
|
||||
/** @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. */
|
||||
#define BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT \
|
||||
1 /**< Default number of Handle Value Notifications that can be queued for transmission. */
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
||||
@@ -221,115 +217,115 @@ enum BLE_GATTS_CFGS {
|
||||
* @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 */
|
||||
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_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_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 */
|
||||
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. */
|
||||
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_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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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.
|
||||
@@ -338,16 +334,16 @@ typedef struct {
|
||||
*
|
||||
* @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.
|
||||
* - @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_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.
|
||||
@@ -358,85 +354,86 @@ typedef struct {
|
||||
* - 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. */
|
||||
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_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. */
|
||||
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. */
|
||||
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. */
|
||||
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). */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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;
|
||||
|
||||
/** @} */
|
||||
@@ -446,9 +443,8 @@ typedef struct {
|
||||
|
||||
/**@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.
|
||||
* @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}
|
||||
@@ -460,8 +456,7 @@ typedef struct {
|
||||
*
|
||||
* @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_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.
|
||||
*/
|
||||
@@ -469,8 +464,8 @@ SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type
|
||||
|
||||
/**@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 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.
|
||||
*
|
||||
@@ -478,42 +473,42 @@ SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type
|
||||
* @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] 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_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));
|
||||
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.
|
||||
/**@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 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 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.
|
||||
* @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] 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.
|
||||
@@ -525,38 +520,37 @@ SVCALL(SD_BLE_GATTS_INCLUDE_ADD, uint32_t, sd_ble_gatts_include_add(uint16_t ser
|
||||
* @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.
|
||||
* @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));
|
||||
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).
|
||||
* @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] 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_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.
|
||||
* @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));
|
||||
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.
|
||||
*
|
||||
@@ -576,11 +570,11 @@ SVCALL(SD_BLE_GATTS_DESCRIPTOR_ADD, uint32_t, sd_ble_gatts_descriptor_add(uint16
|
||||
* @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 ::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));
|
||||
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.
|
||||
*
|
||||
@@ -602,21 +596,21 @@ SVCALL(SD_BLE_GATTS_VALUE_SET, uint32_t, sd_ble_gatts_value_set(uint16_t conn_ha
|
||||
* @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.
|
||||
* @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));
|
||||
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.
|
||||
* @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,
|
||||
* @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
|
||||
@@ -628,17 +622,16 @@ SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t, sd_ble_gatts_value_get(uint16_t conn_ha
|
||||
* 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.
|
||||
* 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:
|
||||
* @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.
|
||||
* - 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.}
|
||||
@@ -659,8 +652,8 @@ SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t, sd_ble_gatts_value_get(uint16_t conn_ha
|
||||
* 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 ::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
|
||||
@@ -668,18 +661,18 @@ SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t, sd_ble_gatts_value_get(uint16_t conn_ha
|
||||
* - 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 ::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_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_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
|
||||
@@ -689,9 +682,9 @@ SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_ga
|
||||
|
||||
/**@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.
|
||||
* @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.
|
||||
*
|
||||
@@ -716,20 +709,20 @@ SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_ga
|
||||
* - 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 ::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 ::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));
|
||||
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.
|
||||
* @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}
|
||||
@@ -748,8 +741,8 @@ SVCALL(SD_BLE_GATTS_SERVICE_CHANGED, uint32_t, sd_ble_gatts_service_changed(uint
|
||||
* 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 ::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.
|
||||
@@ -761,7 +754,8 @@ SVCALL(SD_BLE_GATTS_SERVICE_CHANGED, uint32_t, sd_ble_gatts_service_changed(uint
|
||||
* 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));
|
||||
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.
|
||||
*
|
||||
@@ -776,18 +770,16 @@ SVCALL(SD_BLE_GATTS_RW_AUTHORIZE_REPLY, uint32_t,
|
||||
* 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 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 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.
|
||||
* @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}
|
||||
@@ -815,29 +807,27 @@ SVCALL(SD_BLE_GATTS_SYS_ATTR_SET, uint32_t,
|
||||
/**@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.
|
||||
* 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.
|
||||
* @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[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.
|
||||
@@ -891,8 +881,8 @@ SVCALL(SD_BLE_GATTS_ATTR_GET, uint32_t, sd_ble_gatts_attr_get(uint16_t handle, b
|
||||
* - 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.
|
||||
* - 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.
|
||||
|
||||
@@ -71,8 +71,8 @@ extern "C" {
|
||||
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 \
|
||||
#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. */
|
||||
|
||||
@@ -83,32 +83,32 @@ extern "C" {
|
||||
|
||||
/**@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. */
|
||||
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. */
|
||||
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. */
|
||||
};
|
||||
|
||||
/** @} */
|
||||
@@ -149,8 +149,9 @@ enum BLE_L2CAP_EVTS {
|
||||
#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. */
|
||||
#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. */
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
||||
@@ -171,120 +172,120 @@ enum BLE_L2CAP_EVTS {
|
||||
* @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. */
|
||||
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. */
|
||||
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_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. */
|
||||
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_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 */
|
||||
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_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_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. */
|
||||
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. */
|
||||
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_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. */
|
||||
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;
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -101,77 +101,79 @@ extern "C" {
|
||||
* @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). */
|
||||
#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)
|
||||
#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)
|
||||
#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)
|
||||
#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))
|
||||
@@ -186,20 +188,20 @@ extern "C" {
|
||||
|
||||
/** @brief 128 bit UUID values. */
|
||||
typedef struct {
|
||||
uint8_t uuid128[16]; /**< Little-Endian UUID bytes. */
|
||||
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. */
|
||||
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. */
|
||||
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;
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -86,21 +86,21 @@ This is the offset where the first byte of the SoftDevice hex file is written. *
|
||||
|
||||
/**@brief nRF Master Boot Record API SVC numbers. */
|
||||
enum NRF_MBR_SVCS {
|
||||
SD_MBR_COMMAND = MBR_SVC_BASE, /**< ::sd_mbr_command */
|
||||
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*/
|
||||
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*/
|
||||
};
|
||||
|
||||
/** @} */
|
||||
@@ -117,13 +117,12 @@ enum NRF_MBR_COMMANDS {
|
||||
* 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.
|
||||
* @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.*/
|
||||
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.
|
||||
@@ -132,9 +131,9 @@ typedef struct {
|
||||
* @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.*/
|
||||
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.
|
||||
@@ -160,8 +159,8 @@ typedef struct {
|
||||
* @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. */
|
||||
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
|
||||
@@ -187,7 +186,7 @@ typedef struct {
|
||||
* @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.*/
|
||||
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
|
||||
@@ -198,7 +197,7 @@ typedef struct {
|
||||
* @retval ::NRF_SUCCESS
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/
|
||||
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
|
||||
@@ -208,14 +207,14 @@ typedef struct {
|
||||
* @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. */
|
||||
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;
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -56,10 +56,11 @@ 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).
|
||||
#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
|
||||
}
|
||||
|
||||
@@ -71,26 +71,27 @@ extern "C" {
|
||||
/**@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_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. */ \
|
||||
))
|
||||
#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)))
|
||||
#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)
|
||||
@@ -110,8 +111,8 @@ extern "C" {
|
||||
|
||||
/**@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 */
|
||||
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
|
||||
@@ -161,8 +162,7 @@ __STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority)
|
||||
*
|
||||
* @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.
|
||||
* @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);
|
||||
|
||||
@@ -226,8 +226,7 @@ __STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn);
|
||||
*
|
||||
* @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.
|
||||
* @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);
|
||||
|
||||
@@ -254,8 +253,8 @@ __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
|
||||
* @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.
|
||||
@@ -281,145 +280,162 @@ __STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical
|
||||
|
||||
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
|
||||
|
||||
__STATIC_INLINE int __sd_nvic_irq_disable(void) {
|
||||
int pm = __get_PRIMASK();
|
||||
__disable_irq();
|
||||
return pm;
|
||||
__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 void __sd_nvic_irq_enable(void)
|
||||
{
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
__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();
|
||||
__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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
__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 */
|
||||
|
||||
@@ -151,23 +151,26 @@ the start of the SoftDevice (without MBR)*/
|
||||
/** @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)
|
||||
#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)
|
||||
#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)
|
||||
#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
|
||||
* @{ */
|
||||
@@ -177,13 +180,14 @@ the start of the SoftDevice (without MBR)*/
|
||||
|
||||
/**@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. */
|
||||
#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. */
|
||||
/**@} */
|
||||
|
||||
/** @} */
|
||||
@@ -193,11 +197,11 @@ the start of the SoftDevice (without MBR)*/
|
||||
|
||||
/**@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 */
|
||||
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 */
|
||||
};
|
||||
|
||||
/** @} */
|
||||
@@ -239,34 +243,34 @@ enum NRF_SD_SVCS {
|
||||
|
||||
/**@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.
|
||||
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. */
|
||||
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 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.*/
|
||||
@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.
|
||||
@@ -286,9 +290,9 @@ typedef struct {
|
||||
* @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.
|
||||
* @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);
|
||||
|
||||
@@ -316,20 +320,20 @@ typedef void (*nrf_fault_handler_t)(uint32_t id, uint32_t pc, uint32_t info);
|
||||
*
|
||||
* @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.
|
||||
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_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));
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -81,32 +81,33 @@ extern "C" {
|
||||
#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. \
|
||||
#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. \
|
||||
#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_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_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. */
|
||||
#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)))
|
||||
#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))
|
||||
@@ -121,55 +122,55 @@ extern "C" {
|
||||
|
||||
/**@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
|
||||
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. */
|
||||
@@ -177,80 +178,79 @@ 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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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.
|
||||
@@ -259,66 +259,63 @@ enum NRF_RADIO_CALLBACK_SIGNAL_TYPE {
|
||||
* 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. */
|
||||
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. */
|
||||
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)). */
|
||||
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. */
|
||||
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
|
||||
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
|
||||
};
|
||||
|
||||
/**@} */
|
||||
@@ -333,44 +330,44 @@ 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). */
|
||||
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). */
|
||||
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. */
|
||||
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. */
|
||||
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.
|
||||
@@ -394,17 +391,17 @@ typedef uint8_t soc_ecb_ciphertext_t[SOC_ECB_CIPHERTEXT_LENGTH]; /**< Ciphertext
|
||||
|
||||
/**@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. */
|
||||
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. */
|
||||
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;
|
||||
|
||||
/**@} */
|
||||
@@ -459,8 +456,8 @@ SVCALL(SD_RAND_APPLICATION_BYTES_AVAILABLE_GET, uint32_t, sd_rand_application_by
|
||||
* @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.
|
||||
* @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));
|
||||
|
||||
|
||||
@@ -68,22 +68,23 @@ extern "C" {
|
||||
#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")
|
||||
#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;
|
||||
#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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,26 +12,38 @@
|
||||
// Product strings for auto-configuration
|
||||
// {"PRODUCT_STRING", "CONFIG.YAML"}
|
||||
// YAML paths are relative to `meshtastic/available.d`
|
||||
inline const std::unordered_map<std::string, std::string> configProducts = {{"MESHTOAD", "lora-usb-meshtoad-e22.yaml"},
|
||||
{"MESHSTICK", "lora-meshstick-1262.yaml"},
|
||||
{"MESHADV-PI", "lora-MeshAdv-900M30S.yaml"},
|
||||
{"MeshAdv Mini", "lora-MeshAdv-Mini-900M22S.yaml"},
|
||||
{"POWERPI", "lora-MeshAdv-900M30S.yaml"},
|
||||
{"RAK6421-13300-S1", "lora-RAK6421-13300-slot1.yaml"},
|
||||
{"RAK6421-13300-S2", "lora-RAK6421-13300-slot2.yaml"}};
|
||||
inline const std::unordered_map<std::string, std::string> configProducts = {
|
||||
{"MESHTOAD", "lora-usb-meshtoad-e22.yaml"},
|
||||
{"MESHSTICK", "lora-meshstick-1262.yaml"},
|
||||
{"MESHADV-PI", "lora-MeshAdv-900M30S.yaml"},
|
||||
{"MeshAdv Mini", "lora-MeshAdv-Mini-900M22S.yaml"},
|
||||
{"POWERPI", "lora-MeshAdv-900M30S.yaml"},
|
||||
{"RAK6421-13300-S1", "lora-RAK6421-13300-slot1.yaml"},
|
||||
{"RAK6421-13300-S2", "lora-RAK6421-13300-slot2.yaml"}};
|
||||
|
||||
enum screen_modules { no_screen, x11, fb, st7789, st7735, st7735s, st7796, ili9341, ili9342, ili9486, ili9488, hx8357d };
|
||||
enum touchscreen_modules { no_touchscreen, xpt2046, stmpe610, gt911, ft5x06 };
|
||||
enum portduino_log_level { level_error, level_warn, level_info, level_debug, level_trace };
|
||||
enum lora_module_enum { use_simradio, use_autoconf, use_rf95, use_sx1262, use_sx1268, use_sx1280, use_lr1110, use_lr1120, use_lr1121, use_llcc68 };
|
||||
enum lora_module_enum {
|
||||
use_simradio,
|
||||
use_autoconf,
|
||||
use_rf95,
|
||||
use_sx1262,
|
||||
use_sx1268,
|
||||
use_sx1280,
|
||||
use_lr1110,
|
||||
use_lr1120,
|
||||
use_lr1121,
|
||||
use_llcc68
|
||||
};
|
||||
|
||||
struct pinMapping {
|
||||
std::string config_section;
|
||||
std::string config_name;
|
||||
int pin = RADIOLIB_NC;
|
||||
int gpiochip;
|
||||
int line;
|
||||
bool enabled = false;
|
||||
std::string config_section;
|
||||
std::string config_name;
|
||||
int pin = RADIOLIB_NC;
|
||||
int gpiochip;
|
||||
int line;
|
||||
bool enabled = false;
|
||||
};
|
||||
|
||||
extern std::ofstream traceFile;
|
||||
@@ -47,446 +59,448 @@ void readGPIOFromYaml(YAML::Node sourceNode, pinMapping &destPin, int pinDefault
|
||||
std::string exec(const char *cmd);
|
||||
|
||||
extern struct portduino_config_struct {
|
||||
// Lora
|
||||
std::map<lora_module_enum, std::string> loraModules = {
|
||||
{use_simradio, "sim"}, {use_autoconf, "auto"}, {use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"},
|
||||
{use_sx1280, "sx1280"}, {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
|
||||
|
||||
std::map<screen_modules, std::string> screen_names = {{x11, "X11"}, {fb, "FB"}, {st7789, "ST7789"}, {st7735, "ST7735"},
|
||||
{st7735s, "ST7735S"}, {st7796, "ST7796"}, {ili9341, "ILI9341"}, {ili9342, "ILI9342"},
|
||||
{ili9486, "ILI9486"}, {ili9488, "ILI9488"}, {hx8357d, "HX8357D"}};
|
||||
|
||||
lora_module_enum lora_module;
|
||||
bool has_rfswitch_table = false;
|
||||
uint32_t rfswitch_dio_pins[5] = {RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
|
||||
Module::RfSwitchMode_t rfswitch_table[8];
|
||||
bool force_simradio = false;
|
||||
bool has_device_id = false;
|
||||
uint8_t device_id[16] = {0};
|
||||
std::string lora_spi_dev = "";
|
||||
std::string lora_usb_serial_num = "";
|
||||
int lora_spi_dev_int = 0;
|
||||
int lora_default_gpiochip = 0;
|
||||
int sx126x_max_power = 22;
|
||||
int sx128x_max_power = 13;
|
||||
int lr1110_max_power = 22;
|
||||
int lr1120_max_power = 13;
|
||||
int rf95_max_power = 20;
|
||||
bool dio2_as_rf_switch = false;
|
||||
int dio3_tcxo_voltage = 0;
|
||||
int lora_usb_pid = 0x5512;
|
||||
int lora_usb_vid = 0x1A86;
|
||||
int spiSpeed = 2000000;
|
||||
pinMapping lora_cs_pin = {"Lora", "CS"};
|
||||
pinMapping lora_irq_pin = {"Lora", "IRQ"};
|
||||
pinMapping lora_busy_pin = {"Lora", "Busy"};
|
||||
pinMapping lora_reset_pin = {"Lora", "Reset"};
|
||||
pinMapping lora_txen_pin = {"Lora", "TXen"};
|
||||
pinMapping lora_rxen_pin = {"Lora", "RXen"};
|
||||
pinMapping lora_sx126x_ant_sw_pin = {"Lora", "SX126X_ANT_SW"};
|
||||
|
||||
// GPS
|
||||
bool has_gps = false;
|
||||
|
||||
// I2C
|
||||
std::string i2cdev = "";
|
||||
|
||||
// Display
|
||||
std::string display_spi_dev = "";
|
||||
int display_spi_dev_int = 0;
|
||||
int displayBusFrequency = 40000000;
|
||||
screen_modules displayPanel = no_screen;
|
||||
int displayWidth = 0;
|
||||
int displayHeight = 0;
|
||||
bool displayRGBOrder = false;
|
||||
bool displayBacklightInvert = false;
|
||||
bool displayRotate = false;
|
||||
int displayOffsetRotate = 1;
|
||||
bool displayInvert = false;
|
||||
int displayOffsetX = 0;
|
||||
int displayOffsetY = 0;
|
||||
pinMapping displayDC = {"Display", "DC"};
|
||||
pinMapping displayCS = {"Display", "CS"};
|
||||
pinMapping displayBacklight = {"Display", "Backlight"};
|
||||
pinMapping displayBacklightPWMChannel = {"Display", "BacklightPWMChannel"};
|
||||
pinMapping displayReset = {"Display", "Reset"};
|
||||
|
||||
// Touchscreen
|
||||
std::string touchscreen_spi_dev = "";
|
||||
int touchscreen_spi_dev_int = 0;
|
||||
touchscreen_modules touchscreenModule = no_touchscreen;
|
||||
int touchscreenI2CAddr = -1;
|
||||
int touchscreenBusFrequency = 1000000;
|
||||
int touchscreenRotate = -1;
|
||||
pinMapping touchscreenCS = {"Touchscreen", "CS"};
|
||||
pinMapping touchscreenIRQ = {"Touchscreen", "IRQ"};
|
||||
|
||||
// Input
|
||||
std::string keyboardDevice = "";
|
||||
std::string pointerDevice = "";
|
||||
int tbDirection;
|
||||
pinMapping userButtonPin = {"Input", "User"};
|
||||
pinMapping tbUpPin = {"Input", "TrackballUp"};
|
||||
pinMapping tbDownPin = {"Input", "TrackballDown"};
|
||||
pinMapping tbLeftPin = {"Input", "TrackballLwft"};
|
||||
pinMapping tbRightPin = {"Input", "TrackballRight"};
|
||||
pinMapping tbPressPin = {"Input", "TrackballPress"};
|
||||
|
||||
// Logging
|
||||
portduino_log_level logoutputlevel = level_debug;
|
||||
std::string traceFilename;
|
||||
bool ascii_logs = !isatty(1);
|
||||
bool ascii_logs_explicit = false;
|
||||
|
||||
std::string JSONFilename;
|
||||
meshtastic_PortNum JSONFilter = (_meshtastic_PortNum)0;
|
||||
|
||||
// Webserver
|
||||
std::string webserver_root_path = "";
|
||||
std::string webserver_ssl_key_path = "/etc/meshtasticd/ssl/private_key.pem";
|
||||
std::string webserver_ssl_cert_path = "/etc/meshtasticd/ssl/certificate.pem";
|
||||
int webserverport = -1;
|
||||
|
||||
// HostMetrics
|
||||
std::string hostMetrics_user_command = "";
|
||||
int hostMetrics_interval = 0;
|
||||
int hostMetrics_channel = 0;
|
||||
|
||||
// config
|
||||
int configDisplayMode = 0;
|
||||
bool has_configDisplayMode = false;
|
||||
|
||||
// General
|
||||
std::string mac_address = "";
|
||||
bool mac_address_explicit = false;
|
||||
std::string mac_address_source = "";
|
||||
std::string config_directory = "";
|
||||
std::string available_directory = "/etc/meshtasticd/available.d/";
|
||||
int maxtophone = 100;
|
||||
int MaxNodes = 200;
|
||||
|
||||
pinMapping *all_pins[20] = {&lora_cs_pin,
|
||||
&lora_irq_pin,
|
||||
&lora_busy_pin,
|
||||
&lora_reset_pin,
|
||||
&lora_txen_pin,
|
||||
&lora_rxen_pin,
|
||||
&lora_sx126x_ant_sw_pin,
|
||||
&displayDC,
|
||||
&displayCS,
|
||||
&displayBacklight,
|
||||
&displayBacklightPWMChannel,
|
||||
&displayReset,
|
||||
&touchscreenCS,
|
||||
&touchscreenIRQ,
|
||||
&userButtonPin,
|
||||
&tbUpPin,
|
||||
&tbDownPin,
|
||||
&tbLeftPin,
|
||||
&tbRightPin,
|
||||
&tbPressPin};
|
||||
|
||||
std::string emit_yaml() {
|
||||
YAML::Emitter out;
|
||||
out << YAML::BeginMap;
|
||||
|
||||
// Lora
|
||||
out << YAML::Key << "Lora" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "Module" << YAML::Value << loraModules[lora_module];
|
||||
std::map<lora_module_enum, std::string> loraModules = {
|
||||
{use_simradio, "sim"}, {use_autoconf, "auto"}, {use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"},
|
||||
{use_sx1280, "sx1280"}, {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
|
||||
|
||||
for (auto lora_pin : all_pins) {
|
||||
if (lora_pin->config_section == "Lora" && lora_pin->enabled) {
|
||||
out << YAML::Key << lora_pin->config_name << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "pin" << YAML::Value << lora_pin->pin;
|
||||
out << YAML::Key << "line" << YAML::Value << lora_pin->line;
|
||||
out << YAML::Key << "gpiochip" << YAML::Value << lora_pin->gpiochip;
|
||||
out << YAML::EndMap; // User
|
||||
}
|
||||
}
|
||||
std::map<screen_modules, std::string> screen_names = {{x11, "X11"}, {fb, "FB"}, {st7789, "ST7789"},
|
||||
{st7735, "ST7735"}, {st7735s, "ST7735S"}, {st7796, "ST7796"},
|
||||
{ili9341, "ILI9341"}, {ili9342, "ILI9342"}, {ili9486, "ILI9486"},
|
||||
{ili9488, "ILI9488"}, {hx8357d, "HX8357D"}};
|
||||
|
||||
if (sx126x_max_power != 22)
|
||||
out << YAML::Key << "SX126X_MAX_POWER" << YAML::Value << sx126x_max_power;
|
||||
if (sx128x_max_power != 13)
|
||||
out << YAML::Key << "SX128X_MAX_POWER" << YAML::Value << sx128x_max_power;
|
||||
if (lr1110_max_power != 22)
|
||||
out << YAML::Key << "LR1110_MAX_POWER" << YAML::Value << lr1110_max_power;
|
||||
if (lr1120_max_power != 13)
|
||||
out << YAML::Key << "LR1120_MAX_POWER" << YAML::Value << lr1120_max_power;
|
||||
if (rf95_max_power != 20)
|
||||
out << YAML::Key << "RF95_MAX_POWER" << YAML::Value << rf95_max_power;
|
||||
out << YAML::Key << "DIO2_AS_RF_SWITCH" << YAML::Value << dio2_as_rf_switch;
|
||||
if (dio3_tcxo_voltage != 0)
|
||||
out << YAML::Key << "DIO3_TCXO_VOLTAGE" << YAML::Value << YAML::Precision(3) << (float)dio3_tcxo_voltage / 1000;
|
||||
if (lora_usb_pid != 0x5512)
|
||||
out << YAML::Key << "USB_PID" << YAML::Value << YAML::Hex << lora_usb_pid;
|
||||
if (lora_usb_vid != 0x1A86)
|
||||
out << YAML::Key << "USB_VID" << YAML::Value << YAML::Hex << lora_usb_vid;
|
||||
if (lora_spi_dev != "")
|
||||
out << YAML::Key << "spidev" << YAML::Value << lora_spi_dev;
|
||||
if (lora_usb_serial_num != "")
|
||||
out << YAML::Key << "USB_Serialnum" << YAML::Value << lora_usb_serial_num;
|
||||
out << YAML::Key << "spiSpeed" << YAML::Value << spiSpeed;
|
||||
if (rfswitch_dio_pins[0] != RADIOLIB_NC) {
|
||||
out << YAML::Key << "rfswitch_table" << YAML::Value << YAML::BeginMap;
|
||||
lora_module_enum lora_module;
|
||||
bool has_rfswitch_table = false;
|
||||
uint32_t rfswitch_dio_pins[5] = {RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
|
||||
Module::RfSwitchMode_t rfswitch_table[8];
|
||||
bool force_simradio = false;
|
||||
bool has_device_id = false;
|
||||
uint8_t device_id[16] = {0};
|
||||
std::string lora_spi_dev = "";
|
||||
std::string lora_usb_serial_num = "";
|
||||
int lora_spi_dev_int = 0;
|
||||
int lora_default_gpiochip = 0;
|
||||
int sx126x_max_power = 22;
|
||||
int sx128x_max_power = 13;
|
||||
int lr1110_max_power = 22;
|
||||
int lr1120_max_power = 13;
|
||||
int rf95_max_power = 20;
|
||||
bool dio2_as_rf_switch = false;
|
||||
int dio3_tcxo_voltage = 0;
|
||||
int lora_usb_pid = 0x5512;
|
||||
int lora_usb_vid = 0x1A86;
|
||||
int spiSpeed = 2000000;
|
||||
pinMapping lora_cs_pin = {"Lora", "CS"};
|
||||
pinMapping lora_irq_pin = {"Lora", "IRQ"};
|
||||
pinMapping lora_busy_pin = {"Lora", "Busy"};
|
||||
pinMapping lora_reset_pin = {"Lora", "Reset"};
|
||||
pinMapping lora_txen_pin = {"Lora", "TXen"};
|
||||
pinMapping lora_rxen_pin = {"Lora", "RXen"};
|
||||
pinMapping lora_sx126x_ant_sw_pin = {"Lora", "SX126X_ANT_SW"};
|
||||
|
||||
out << YAML::Key << "pins";
|
||||
out << YAML::Value << YAML::Flow << YAML::BeginSeq;
|
||||
// GPS
|
||||
bool has_gps = false;
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
// set up the pin array first
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO5)
|
||||
out << "DIO5";
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO6)
|
||||
out << "DIO6";
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO7)
|
||||
out << "DIO7";
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO8)
|
||||
out << "DIO8";
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO10)
|
||||
out << "DIO10";
|
||||
}
|
||||
out << YAML::EndSeq;
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
out << YAML::Key << "MODE_STBY";
|
||||
break;
|
||||
case 1:
|
||||
out << YAML::Key << "MODE_RX";
|
||||
break;
|
||||
case 2:
|
||||
out << YAML::Key << "MODE_TX";
|
||||
break;
|
||||
case 3:
|
||||
out << YAML::Key << "MODE_TX_HP";
|
||||
break;
|
||||
case 4:
|
||||
out << YAML::Key << "MODE_TX_HF";
|
||||
break;
|
||||
case 5:
|
||||
out << YAML::Key << "MODE_GNSS";
|
||||
break;
|
||||
case 6:
|
||||
out << YAML::Key << "MODE_WIFI";
|
||||
break;
|
||||
}
|
||||
|
||||
out << YAML::Value << YAML::Flow << YAML::BeginSeq;
|
||||
for (int j = 0; j < 5; j++) {
|
||||
if (rfswitch_table[i].values[j] == HIGH) {
|
||||
out << "HIGH";
|
||||
} else {
|
||||
out << "LOW";
|
||||
}
|
||||
}
|
||||
out << YAML::EndSeq;
|
||||
}
|
||||
out << YAML::EndMap; // rfswitch_table
|
||||
}
|
||||
out << YAML::EndMap; // Lora
|
||||
|
||||
if (i2cdev != "") {
|
||||
out << YAML::Key << "I2C" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "I2CDevice" << YAML::Value << i2cdev;
|
||||
out << YAML::EndMap; // I2C
|
||||
}
|
||||
// I2C
|
||||
std::string i2cdev = "";
|
||||
|
||||
// Display
|
||||
if (displayPanel != no_screen) {
|
||||
out << YAML::Key << "Display" << YAML::Value << YAML::BeginMap;
|
||||
for (auto &screen_name : screen_names) {
|
||||
if (displayPanel == screen_name.first)
|
||||
out << YAML::Key << "Module" << YAML::Value << screen_name.second;
|
||||
}
|
||||
for (auto display_pin : all_pins) {
|
||||
if (display_pin->config_section == "Display" && display_pin->enabled) {
|
||||
out << YAML::Key << display_pin->config_name << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "pin" << YAML::Value << display_pin->pin;
|
||||
out << YAML::Key << "line" << YAML::Value << display_pin->line;
|
||||
out << YAML::Key << "gpiochip" << YAML::Value << display_pin->gpiochip;
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
}
|
||||
out << YAML::Key << "spidev" << YAML::Value << display_spi_dev;
|
||||
out << YAML::Key << "BusFrequency" << YAML::Value << displayBusFrequency;
|
||||
if (displayWidth)
|
||||
out << YAML::Key << "Width" << YAML::Value << displayWidth;
|
||||
if (displayHeight)
|
||||
out << YAML::Key << "Height" << YAML::Value << displayHeight;
|
||||
if (displayRGBOrder)
|
||||
out << YAML::Key << "RGBOrder" << YAML::Value << true;
|
||||
if (displayBacklightInvert)
|
||||
out << YAML::Key << "BacklightInvert" << YAML::Value << true;
|
||||
if (displayRotate)
|
||||
out << YAML::Key << "Rotate" << YAML::Value << true;
|
||||
if (displayInvert)
|
||||
out << YAML::Key << "Invert" << YAML::Value << true;
|
||||
if (displayOffsetX)
|
||||
out << YAML::Key << "OffsetX" << YAML::Value << displayOffsetX;
|
||||
if (displayOffsetY)
|
||||
out << YAML::Key << "OffsetY" << YAML::Value << displayOffsetY;
|
||||
|
||||
out << YAML::Key << "OffsetRotate" << YAML::Value << displayOffsetRotate;
|
||||
|
||||
out << YAML::EndMap; // Display
|
||||
}
|
||||
std::string display_spi_dev = "";
|
||||
int display_spi_dev_int = 0;
|
||||
int displayBusFrequency = 40000000;
|
||||
screen_modules displayPanel = no_screen;
|
||||
int displayWidth = 0;
|
||||
int displayHeight = 0;
|
||||
bool displayRGBOrder = false;
|
||||
bool displayBacklightInvert = false;
|
||||
bool displayRotate = false;
|
||||
int displayOffsetRotate = 1;
|
||||
bool displayInvert = false;
|
||||
int displayOffsetX = 0;
|
||||
int displayOffsetY = 0;
|
||||
pinMapping displayDC = {"Display", "DC"};
|
||||
pinMapping displayCS = {"Display", "CS"};
|
||||
pinMapping displayBacklight = {"Display", "Backlight"};
|
||||
pinMapping displayBacklightPWMChannel = {"Display", "BacklightPWMChannel"};
|
||||
pinMapping displayReset = {"Display", "Reset"};
|
||||
|
||||
// Touchscreen
|
||||
if (touchscreen_spi_dev != "") {
|
||||
out << YAML::Key << "Touchscreen" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "spidev" << YAML::Value << touchscreen_spi_dev;
|
||||
out << YAML::Key << "BusFrequency" << YAML::Value << touchscreenBusFrequency;
|
||||
switch (touchscreenModule) {
|
||||
case xpt2046:
|
||||
out << YAML::Key << "Module" << YAML::Value << "XPT2046";
|
||||
case stmpe610:
|
||||
out << YAML::Key << "Module" << YAML::Value << "STMPE610";
|
||||
case gt911:
|
||||
out << YAML::Key << "Module" << YAML::Value << "GT911";
|
||||
case ft5x06:
|
||||
out << YAML::Key << "Module" << YAML::Value << "FT5x06";
|
||||
}
|
||||
for (auto touchscreen_pin : all_pins) {
|
||||
if (touchscreen_pin->config_section == "Touchscreen" && touchscreen_pin->enabled) {
|
||||
out << YAML::Key << touchscreen_pin->config_name << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "pin" << YAML::Value << touchscreen_pin->pin;
|
||||
out << YAML::Key << "line" << YAML::Value << touchscreen_pin->line;
|
||||
out << YAML::Key << "gpiochip" << YAML::Value << touchscreen_pin->gpiochip;
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
}
|
||||
if (touchscreenRotate != -1)
|
||||
out << YAML::Key << "Rotate" << YAML::Value << touchscreenRotate;
|
||||
if (touchscreenI2CAddr != -1)
|
||||
out << YAML::Key << "I2CAddr" << YAML::Value << touchscreenI2CAddr;
|
||||
out << YAML::EndMap; // Touchscreen
|
||||
}
|
||||
std::string touchscreen_spi_dev = "";
|
||||
int touchscreen_spi_dev_int = 0;
|
||||
touchscreen_modules touchscreenModule = no_touchscreen;
|
||||
int touchscreenI2CAddr = -1;
|
||||
int touchscreenBusFrequency = 1000000;
|
||||
int touchscreenRotate = -1;
|
||||
pinMapping touchscreenCS = {"Touchscreen", "CS"};
|
||||
pinMapping touchscreenIRQ = {"Touchscreen", "IRQ"};
|
||||
|
||||
// Input
|
||||
out << YAML::Key << "Input" << YAML::Value << YAML::BeginMap;
|
||||
if (keyboardDevice != "")
|
||||
out << YAML::Key << "KeyboardDevice" << YAML::Value << keyboardDevice;
|
||||
if (pointerDevice != "")
|
||||
out << YAML::Key << "PointerDevice" << YAML::Value << pointerDevice;
|
||||
std::string keyboardDevice = "";
|
||||
std::string pointerDevice = "";
|
||||
int tbDirection;
|
||||
pinMapping userButtonPin = {"Input", "User"};
|
||||
pinMapping tbUpPin = {"Input", "TrackballUp"};
|
||||
pinMapping tbDownPin = {"Input", "TrackballDown"};
|
||||
pinMapping tbLeftPin = {"Input", "TrackballLwft"};
|
||||
pinMapping tbRightPin = {"Input", "TrackballRight"};
|
||||
pinMapping tbPressPin = {"Input", "TrackballPress"};
|
||||
|
||||
for (auto input_pin : all_pins) {
|
||||
if (input_pin->config_section == "Input" && input_pin->enabled) {
|
||||
out << YAML::Key << input_pin->config_name << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "pin" << YAML::Value << input_pin->pin;
|
||||
out << YAML::Key << "line" << YAML::Value << input_pin->line;
|
||||
out << YAML::Key << "gpiochip" << YAML::Value << input_pin->gpiochip;
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
}
|
||||
if (tbDirection == 3)
|
||||
out << YAML::Key << "TrackballDirection" << YAML::Value << "FALLING";
|
||||
// Logging
|
||||
portduino_log_level logoutputlevel = level_debug;
|
||||
std::string traceFilename;
|
||||
bool ascii_logs = !isatty(1);
|
||||
bool ascii_logs_explicit = false;
|
||||
|
||||
out << YAML::EndMap; // Input
|
||||
|
||||
out << YAML::Key << "Logging" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "LogLevel" << YAML::Value;
|
||||
switch (logoutputlevel) {
|
||||
case level_error:
|
||||
out << "error";
|
||||
break;
|
||||
case level_warn:
|
||||
out << "warn";
|
||||
break;
|
||||
case level_info:
|
||||
out << "info";
|
||||
break;
|
||||
case level_debug:
|
||||
out << "debug";
|
||||
break;
|
||||
case level_trace:
|
||||
out << "trace";
|
||||
break;
|
||||
}
|
||||
if (traceFilename != "")
|
||||
out << YAML::Key << "TraceFile" << YAML::Value << traceFilename;
|
||||
if (JSONFilename != "") {
|
||||
out << YAML::Key << "JSONFile" << YAML::Value << JSONFilename;
|
||||
if (JSONFilter == meshtastic_PortNum_TEXT_MESSAGE_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "textmessage";
|
||||
else if (JSONFilter == meshtastic_PortNum_TELEMETRY_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "telemetry";
|
||||
else if (JSONFilter == meshtastic_PortNum_NODEINFO_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "nodeinfo";
|
||||
else if (JSONFilter == meshtastic_PortNum_POSITION_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "position";
|
||||
else if (JSONFilter == meshtastic_PortNum_WAYPOINT_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "waypoint";
|
||||
else if (JSONFilter == meshtastic_PortNum_NEIGHBORINFO_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "neighborinfo";
|
||||
else if (JSONFilter == meshtastic_PortNum_TRACEROUTE_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "traceroute";
|
||||
else if (JSONFilter == meshtastic_PortNum_DETECTION_SENSOR_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "detection";
|
||||
else if (JSONFilter == meshtastic_PortNum_PAXCOUNTER_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "paxcounter";
|
||||
else if (JSONFilter == meshtastic_PortNum_REMOTE_HARDWARE_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "remotehardware";
|
||||
}
|
||||
if (ascii_logs_explicit) {
|
||||
out << YAML::Key << "AsciiLogs" << YAML::Value << ascii_logs;
|
||||
}
|
||||
out << YAML::EndMap; // Logging
|
||||
std::string JSONFilename;
|
||||
meshtastic_PortNum JSONFilter = (_meshtastic_PortNum)0;
|
||||
|
||||
// Webserver
|
||||
if (webserver_root_path != "") {
|
||||
out << YAML::Key << "Webserver" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "RootPath" << YAML::Value << webserver_root_path;
|
||||
out << YAML::Key << "SSLKey" << YAML::Value << webserver_ssl_key_path;
|
||||
out << YAML::Key << "SSLCert" << YAML::Value << webserver_ssl_cert_path;
|
||||
out << YAML::Key << "Port" << YAML::Value << webserverport;
|
||||
out << YAML::EndMap; // Webserver
|
||||
}
|
||||
std::string webserver_root_path = "";
|
||||
std::string webserver_ssl_key_path = "/etc/meshtasticd/ssl/private_key.pem";
|
||||
std::string webserver_ssl_cert_path = "/etc/meshtasticd/ssl/certificate.pem";
|
||||
int webserverport = -1;
|
||||
|
||||
// HostMetrics
|
||||
if (hostMetrics_user_command != "") {
|
||||
out << YAML::Key << "HostMetrics" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "UserStringCommand" << YAML::Value << hostMetrics_user_command;
|
||||
out << YAML::Key << "ReportInterval" << YAML::Value << hostMetrics_interval;
|
||||
out << YAML::Key << "Channel" << YAML::Value << hostMetrics_channel;
|
||||
|
||||
out << YAML::EndMap; // HostMetrics
|
||||
}
|
||||
std::string hostMetrics_user_command = "";
|
||||
int hostMetrics_interval = 0;
|
||||
int hostMetrics_channel = 0;
|
||||
|
||||
// config
|
||||
if (has_configDisplayMode) {
|
||||
out << YAML::Key << "Config" << YAML::Value << YAML::BeginMap;
|
||||
switch (configDisplayMode) {
|
||||
case meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR:
|
||||
out << YAML::Key << "DisplayMode" << YAML::Value << "TWOCOLOR";
|
||||
break;
|
||||
case meshtastic_Config_DisplayConfig_DisplayMode_INVERTED:
|
||||
out << YAML::Key << "DisplayMode" << YAML::Value << "INVERTED";
|
||||
break;
|
||||
case meshtastic_Config_DisplayConfig_DisplayMode_COLOR:
|
||||
out << YAML::Key << "DisplayMode" << YAML::Value << "COLOR";
|
||||
break;
|
||||
case meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT:
|
||||
out << YAML::Key << "DisplayMode" << YAML::Value << "DEFAULT";
|
||||
break;
|
||||
}
|
||||
|
||||
out << YAML::EndMap; // Config
|
||||
}
|
||||
int configDisplayMode = 0;
|
||||
bool has_configDisplayMode = false;
|
||||
|
||||
// General
|
||||
out << YAML::Key << "General" << YAML::Value << YAML::BeginMap;
|
||||
if (config_directory != "")
|
||||
out << YAML::Key << "ConfigDirectory" << YAML::Value << config_directory;
|
||||
if (mac_address_explicit)
|
||||
out << YAML::Key << "MACAddress" << YAML::Value << mac_address;
|
||||
if (mac_address_source != "")
|
||||
out << YAML::Key << "MACAddressSource" << YAML::Value << mac_address_source;
|
||||
if (available_directory != "")
|
||||
out << YAML::Key << "AvailableDirectory" << YAML::Value << available_directory;
|
||||
out << YAML::Key << "MaxMessageQueue" << YAML::Value << maxtophone;
|
||||
out << YAML::Key << "MaxNodes" << YAML::Value << MaxNodes;
|
||||
out << YAML::EndMap; // General
|
||||
return out.c_str();
|
||||
}
|
||||
std::string mac_address = "";
|
||||
bool mac_address_explicit = false;
|
||||
std::string mac_address_source = "";
|
||||
std::string config_directory = "";
|
||||
std::string available_directory = "/etc/meshtasticd/available.d/";
|
||||
int maxtophone = 100;
|
||||
int MaxNodes = 200;
|
||||
|
||||
pinMapping *all_pins[20] = {&lora_cs_pin,
|
||||
&lora_irq_pin,
|
||||
&lora_busy_pin,
|
||||
&lora_reset_pin,
|
||||
&lora_txen_pin,
|
||||
&lora_rxen_pin,
|
||||
&lora_sx126x_ant_sw_pin,
|
||||
&displayDC,
|
||||
&displayCS,
|
||||
&displayBacklight,
|
||||
&displayBacklightPWMChannel,
|
||||
&displayReset,
|
||||
&touchscreenCS,
|
||||
&touchscreenIRQ,
|
||||
&userButtonPin,
|
||||
&tbUpPin,
|
||||
&tbDownPin,
|
||||
&tbLeftPin,
|
||||
&tbRightPin,
|
||||
&tbPressPin};
|
||||
|
||||
std::string emit_yaml()
|
||||
{
|
||||
YAML::Emitter out;
|
||||
out << YAML::BeginMap;
|
||||
|
||||
// Lora
|
||||
out << YAML::Key << "Lora" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "Module" << YAML::Value << loraModules[lora_module];
|
||||
|
||||
for (auto lora_pin : all_pins) {
|
||||
if (lora_pin->config_section == "Lora" && lora_pin->enabled) {
|
||||
out << YAML::Key << lora_pin->config_name << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "pin" << YAML::Value << lora_pin->pin;
|
||||
out << YAML::Key << "line" << YAML::Value << lora_pin->line;
|
||||
out << YAML::Key << "gpiochip" << YAML::Value << lora_pin->gpiochip;
|
||||
out << YAML::EndMap; // User
|
||||
}
|
||||
}
|
||||
|
||||
if (sx126x_max_power != 22)
|
||||
out << YAML::Key << "SX126X_MAX_POWER" << YAML::Value << sx126x_max_power;
|
||||
if (sx128x_max_power != 13)
|
||||
out << YAML::Key << "SX128X_MAX_POWER" << YAML::Value << sx128x_max_power;
|
||||
if (lr1110_max_power != 22)
|
||||
out << YAML::Key << "LR1110_MAX_POWER" << YAML::Value << lr1110_max_power;
|
||||
if (lr1120_max_power != 13)
|
||||
out << YAML::Key << "LR1120_MAX_POWER" << YAML::Value << lr1120_max_power;
|
||||
if (rf95_max_power != 20)
|
||||
out << YAML::Key << "RF95_MAX_POWER" << YAML::Value << rf95_max_power;
|
||||
out << YAML::Key << "DIO2_AS_RF_SWITCH" << YAML::Value << dio2_as_rf_switch;
|
||||
if (dio3_tcxo_voltage != 0)
|
||||
out << YAML::Key << "DIO3_TCXO_VOLTAGE" << YAML::Value << YAML::Precision(3) << (float)dio3_tcxo_voltage / 1000;
|
||||
if (lora_usb_pid != 0x5512)
|
||||
out << YAML::Key << "USB_PID" << YAML::Value << YAML::Hex << lora_usb_pid;
|
||||
if (lora_usb_vid != 0x1A86)
|
||||
out << YAML::Key << "USB_VID" << YAML::Value << YAML::Hex << lora_usb_vid;
|
||||
if (lora_spi_dev != "")
|
||||
out << YAML::Key << "spidev" << YAML::Value << lora_spi_dev;
|
||||
if (lora_usb_serial_num != "")
|
||||
out << YAML::Key << "USB_Serialnum" << YAML::Value << lora_usb_serial_num;
|
||||
out << YAML::Key << "spiSpeed" << YAML::Value << spiSpeed;
|
||||
if (rfswitch_dio_pins[0] != RADIOLIB_NC) {
|
||||
out << YAML::Key << "rfswitch_table" << YAML::Value << YAML::BeginMap;
|
||||
|
||||
out << YAML::Key << "pins";
|
||||
out << YAML::Value << YAML::Flow << YAML::BeginSeq;
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
// set up the pin array first
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO5)
|
||||
out << "DIO5";
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO6)
|
||||
out << "DIO6";
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO7)
|
||||
out << "DIO7";
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO8)
|
||||
out << "DIO8";
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO10)
|
||||
out << "DIO10";
|
||||
}
|
||||
out << YAML::EndSeq;
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
out << YAML::Key << "MODE_STBY";
|
||||
break;
|
||||
case 1:
|
||||
out << YAML::Key << "MODE_RX";
|
||||
break;
|
||||
case 2:
|
||||
out << YAML::Key << "MODE_TX";
|
||||
break;
|
||||
case 3:
|
||||
out << YAML::Key << "MODE_TX_HP";
|
||||
break;
|
||||
case 4:
|
||||
out << YAML::Key << "MODE_TX_HF";
|
||||
break;
|
||||
case 5:
|
||||
out << YAML::Key << "MODE_GNSS";
|
||||
break;
|
||||
case 6:
|
||||
out << YAML::Key << "MODE_WIFI";
|
||||
break;
|
||||
}
|
||||
|
||||
out << YAML::Value << YAML::Flow << YAML::BeginSeq;
|
||||
for (int j = 0; j < 5; j++) {
|
||||
if (rfswitch_table[i].values[j] == HIGH) {
|
||||
out << "HIGH";
|
||||
} else {
|
||||
out << "LOW";
|
||||
}
|
||||
}
|
||||
out << YAML::EndSeq;
|
||||
}
|
||||
out << YAML::EndMap; // rfswitch_table
|
||||
}
|
||||
out << YAML::EndMap; // Lora
|
||||
|
||||
if (i2cdev != "") {
|
||||
out << YAML::Key << "I2C" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "I2CDevice" << YAML::Value << i2cdev;
|
||||
out << YAML::EndMap; // I2C
|
||||
}
|
||||
|
||||
// Display
|
||||
if (displayPanel != no_screen) {
|
||||
out << YAML::Key << "Display" << YAML::Value << YAML::BeginMap;
|
||||
for (auto &screen_name : screen_names) {
|
||||
if (displayPanel == screen_name.first)
|
||||
out << YAML::Key << "Module" << YAML::Value << screen_name.second;
|
||||
}
|
||||
for (auto display_pin : all_pins) {
|
||||
if (display_pin->config_section == "Display" && display_pin->enabled) {
|
||||
out << YAML::Key << display_pin->config_name << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "pin" << YAML::Value << display_pin->pin;
|
||||
out << YAML::Key << "line" << YAML::Value << display_pin->line;
|
||||
out << YAML::Key << "gpiochip" << YAML::Value << display_pin->gpiochip;
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
}
|
||||
out << YAML::Key << "spidev" << YAML::Value << display_spi_dev;
|
||||
out << YAML::Key << "BusFrequency" << YAML::Value << displayBusFrequency;
|
||||
if (displayWidth)
|
||||
out << YAML::Key << "Width" << YAML::Value << displayWidth;
|
||||
if (displayHeight)
|
||||
out << YAML::Key << "Height" << YAML::Value << displayHeight;
|
||||
if (displayRGBOrder)
|
||||
out << YAML::Key << "RGBOrder" << YAML::Value << true;
|
||||
if (displayBacklightInvert)
|
||||
out << YAML::Key << "BacklightInvert" << YAML::Value << true;
|
||||
if (displayRotate)
|
||||
out << YAML::Key << "Rotate" << YAML::Value << true;
|
||||
if (displayInvert)
|
||||
out << YAML::Key << "Invert" << YAML::Value << true;
|
||||
if (displayOffsetX)
|
||||
out << YAML::Key << "OffsetX" << YAML::Value << displayOffsetX;
|
||||
if (displayOffsetY)
|
||||
out << YAML::Key << "OffsetY" << YAML::Value << displayOffsetY;
|
||||
|
||||
out << YAML::Key << "OffsetRotate" << YAML::Value << displayOffsetRotate;
|
||||
|
||||
out << YAML::EndMap; // Display
|
||||
}
|
||||
|
||||
// Touchscreen
|
||||
if (touchscreen_spi_dev != "") {
|
||||
out << YAML::Key << "Touchscreen" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "spidev" << YAML::Value << touchscreen_spi_dev;
|
||||
out << YAML::Key << "BusFrequency" << YAML::Value << touchscreenBusFrequency;
|
||||
switch (touchscreenModule) {
|
||||
case xpt2046:
|
||||
out << YAML::Key << "Module" << YAML::Value << "XPT2046";
|
||||
case stmpe610:
|
||||
out << YAML::Key << "Module" << YAML::Value << "STMPE610";
|
||||
case gt911:
|
||||
out << YAML::Key << "Module" << YAML::Value << "GT911";
|
||||
case ft5x06:
|
||||
out << YAML::Key << "Module" << YAML::Value << "FT5x06";
|
||||
}
|
||||
for (auto touchscreen_pin : all_pins) {
|
||||
if (touchscreen_pin->config_section == "Touchscreen" && touchscreen_pin->enabled) {
|
||||
out << YAML::Key << touchscreen_pin->config_name << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "pin" << YAML::Value << touchscreen_pin->pin;
|
||||
out << YAML::Key << "line" << YAML::Value << touchscreen_pin->line;
|
||||
out << YAML::Key << "gpiochip" << YAML::Value << touchscreen_pin->gpiochip;
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
}
|
||||
if (touchscreenRotate != -1)
|
||||
out << YAML::Key << "Rotate" << YAML::Value << touchscreenRotate;
|
||||
if (touchscreenI2CAddr != -1)
|
||||
out << YAML::Key << "I2CAddr" << YAML::Value << touchscreenI2CAddr;
|
||||
out << YAML::EndMap; // Touchscreen
|
||||
}
|
||||
|
||||
// Input
|
||||
out << YAML::Key << "Input" << YAML::Value << YAML::BeginMap;
|
||||
if (keyboardDevice != "")
|
||||
out << YAML::Key << "KeyboardDevice" << YAML::Value << keyboardDevice;
|
||||
if (pointerDevice != "")
|
||||
out << YAML::Key << "PointerDevice" << YAML::Value << pointerDevice;
|
||||
|
||||
for (auto input_pin : all_pins) {
|
||||
if (input_pin->config_section == "Input" && input_pin->enabled) {
|
||||
out << YAML::Key << input_pin->config_name << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "pin" << YAML::Value << input_pin->pin;
|
||||
out << YAML::Key << "line" << YAML::Value << input_pin->line;
|
||||
out << YAML::Key << "gpiochip" << YAML::Value << input_pin->gpiochip;
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
}
|
||||
if (tbDirection == 3)
|
||||
out << YAML::Key << "TrackballDirection" << YAML::Value << "FALLING";
|
||||
|
||||
out << YAML::EndMap; // Input
|
||||
|
||||
out << YAML::Key << "Logging" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "LogLevel" << YAML::Value;
|
||||
switch (logoutputlevel) {
|
||||
case level_error:
|
||||
out << "error";
|
||||
break;
|
||||
case level_warn:
|
||||
out << "warn";
|
||||
break;
|
||||
case level_info:
|
||||
out << "info";
|
||||
break;
|
||||
case level_debug:
|
||||
out << "debug";
|
||||
break;
|
||||
case level_trace:
|
||||
out << "trace";
|
||||
break;
|
||||
}
|
||||
if (traceFilename != "")
|
||||
out << YAML::Key << "TraceFile" << YAML::Value << traceFilename;
|
||||
if (JSONFilename != "") {
|
||||
out << YAML::Key << "JSONFile" << YAML::Value << JSONFilename;
|
||||
if (JSONFilter == meshtastic_PortNum_TEXT_MESSAGE_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "textmessage";
|
||||
else if (JSONFilter == meshtastic_PortNum_TELEMETRY_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "telemetry";
|
||||
else if (JSONFilter == meshtastic_PortNum_NODEINFO_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "nodeinfo";
|
||||
else if (JSONFilter == meshtastic_PortNum_POSITION_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "position";
|
||||
else if (JSONFilter == meshtastic_PortNum_WAYPOINT_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "waypoint";
|
||||
else if (JSONFilter == meshtastic_PortNum_NEIGHBORINFO_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "neighborinfo";
|
||||
else if (JSONFilter == meshtastic_PortNum_TRACEROUTE_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "traceroute";
|
||||
else if (JSONFilter == meshtastic_PortNum_DETECTION_SENSOR_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "detection";
|
||||
else if (JSONFilter == meshtastic_PortNum_PAXCOUNTER_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "paxcounter";
|
||||
else if (JSONFilter == meshtastic_PortNum_REMOTE_HARDWARE_APP)
|
||||
out << YAML::Key << "JSONFilter" << YAML::Value << "remotehardware";
|
||||
}
|
||||
if (ascii_logs_explicit) {
|
||||
out << YAML::Key << "AsciiLogs" << YAML::Value << ascii_logs;
|
||||
}
|
||||
out << YAML::EndMap; // Logging
|
||||
|
||||
// Webserver
|
||||
if (webserver_root_path != "") {
|
||||
out << YAML::Key << "Webserver" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "RootPath" << YAML::Value << webserver_root_path;
|
||||
out << YAML::Key << "SSLKey" << YAML::Value << webserver_ssl_key_path;
|
||||
out << YAML::Key << "SSLCert" << YAML::Value << webserver_ssl_cert_path;
|
||||
out << YAML::Key << "Port" << YAML::Value << webserverport;
|
||||
out << YAML::EndMap; // Webserver
|
||||
}
|
||||
|
||||
// HostMetrics
|
||||
if (hostMetrics_user_command != "") {
|
||||
out << YAML::Key << "HostMetrics" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "UserStringCommand" << YAML::Value << hostMetrics_user_command;
|
||||
out << YAML::Key << "ReportInterval" << YAML::Value << hostMetrics_interval;
|
||||
out << YAML::Key << "Channel" << YAML::Value << hostMetrics_channel;
|
||||
|
||||
out << YAML::EndMap; // HostMetrics
|
||||
}
|
||||
|
||||
// config
|
||||
if (has_configDisplayMode) {
|
||||
out << YAML::Key << "Config" << YAML::Value << YAML::BeginMap;
|
||||
switch (configDisplayMode) {
|
||||
case meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR:
|
||||
out << YAML::Key << "DisplayMode" << YAML::Value << "TWOCOLOR";
|
||||
break;
|
||||
case meshtastic_Config_DisplayConfig_DisplayMode_INVERTED:
|
||||
out << YAML::Key << "DisplayMode" << YAML::Value << "INVERTED";
|
||||
break;
|
||||
case meshtastic_Config_DisplayConfig_DisplayMode_COLOR:
|
||||
out << YAML::Key << "DisplayMode" << YAML::Value << "COLOR";
|
||||
break;
|
||||
case meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT:
|
||||
out << YAML::Key << "DisplayMode" << YAML::Value << "DEFAULT";
|
||||
break;
|
||||
}
|
||||
|
||||
out << YAML::EndMap; // Config
|
||||
}
|
||||
|
||||
// General
|
||||
out << YAML::Key << "General" << YAML::Value << YAML::BeginMap;
|
||||
if (config_directory != "")
|
||||
out << YAML::Key << "ConfigDirectory" << YAML::Value << config_directory;
|
||||
if (mac_address_explicit)
|
||||
out << YAML::Key << "MACAddress" << YAML::Value << mac_address;
|
||||
if (mac_address_source != "")
|
||||
out << YAML::Key << "MACAddressSource" << YAML::Value << mac_address_source;
|
||||
if (available_directory != "")
|
||||
out << YAML::Key << "AvailableDirectory" << YAML::Value << available_directory;
|
||||
out << YAML::Key << "MaxMessageQueue" << YAML::Value << maxtophone;
|
||||
out << YAML::Key << "MaxNodes" << YAML::Value << MaxNodes;
|
||||
out << YAML::EndMap; // General
|
||||
return out.c_str();
|
||||
}
|
||||
} portduino_config;
|
||||
+280
-248
@@ -2,311 +2,341 @@
|
||||
#include "MeshService.h"
|
||||
#include "Router.h"
|
||||
|
||||
SimRadio::SimRadio() : NotifiedWorkerThread("SimRadio") { instance = this; }
|
||||
SimRadio::SimRadio() : NotifiedWorkerThread("SimRadio")
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
|
||||
SimRadio *SimRadio::instance;
|
||||
|
||||
ErrorCode SimRadio::send(meshtastic_MeshPacket *p) {
|
||||
printPacket("enqueuing for send", p);
|
||||
ErrorCode SimRadio::send(meshtastic_MeshPacket *p)
|
||||
{
|
||||
printPacket("enqueuing for send", p);
|
||||
|
||||
bool dropped = false;
|
||||
ErrorCode res = txQueue.enqueue(p, &dropped) ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||
bool dropped = false;
|
||||
ErrorCode res = txQueue.enqueue(p, &dropped) ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||
|
||||
if (dropped) {
|
||||
txDrop++;
|
||||
}
|
||||
if (dropped) {
|
||||
txDrop++;
|
||||
}
|
||||
|
||||
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
|
||||
packetPool.release(p);
|
||||
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
|
||||
packetPool.release(p);
|
||||
return res;
|
||||
}
|
||||
|
||||
// set (random) transmit delay to let others reconfigure their radio,
|
||||
// to avoid collisions and implement timing-based flooding
|
||||
LOG_DEBUG("Set random delay before tx");
|
||||
setTransmitDelay();
|
||||
return res;
|
||||
}
|
||||
|
||||
// set (random) transmit delay to let others reconfigure their radio,
|
||||
// to avoid collisions and implement timing-based flooding
|
||||
LOG_DEBUG("Set random delay before tx");
|
||||
setTransmitDelay();
|
||||
return res;
|
||||
}
|
||||
|
||||
void SimRadio::setTransmitDelay() {
|
||||
meshtastic_MeshPacket *p = txQueue.getFront();
|
||||
// We want all sending/receiving to be done by our daemon thread.
|
||||
// We use a delay here because this packet might have been sent in response to a packet we just received.
|
||||
// So we want to make sure the other side has had a chance to reconfigure its radio.
|
||||
void SimRadio::setTransmitDelay()
|
||||
{
|
||||
meshtastic_MeshPacket *p = txQueue.getFront();
|
||||
// We want all sending/receiving to be done by our daemon thread.
|
||||
// We use a delay here because this packet might have been sent in response to a packet we just received.
|
||||
// So we want to make sure the other side has had a chance to reconfigure its radio.
|
||||
|
||||
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
|
||||
* This assumption is valid because of the offset generated by the radio to account for the noise
|
||||
* floor.
|
||||
*/
|
||||
if (p->rx_snr == 0 && p->rx_rssi == 0) {
|
||||
startTransmitTimer(true);
|
||||
} else {
|
||||
// If there is a SNR, start a timer scaled based on that SNR.
|
||||
LOG_DEBUG("rx_snr found. hop_limit:%d rx_snr:%f", p->hop_limit, p->rx_snr);
|
||||
startTransmitTimerRebroadcast(p);
|
||||
}
|
||||
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
|
||||
* This assumption is valid because of the offset generated by the radio to account for the noise
|
||||
* floor.
|
||||
*/
|
||||
if (p->rx_snr == 0 && p->rx_rssi == 0) {
|
||||
startTransmitTimer(true);
|
||||
} else {
|
||||
// If there is a SNR, start a timer scaled based on that SNR.
|
||||
LOG_DEBUG("rx_snr found. hop_limit:%d rx_snr:%f", p->hop_limit, p->rx_snr);
|
||||
startTransmitTimerRebroadcast(p);
|
||||
}
|
||||
}
|
||||
|
||||
void SimRadio::startTransmitTimer(bool withDelay) {
|
||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||
if (!txQueue.empty()) {
|
||||
uint32_t delayMsec = !withDelay ? 1 : getTxDelayMsec();
|
||||
// LOG_DEBUG("xmit timer %d", delay);
|
||||
notifyLater(delayMsec, TRANSMIT_DELAY_COMPLETED, false);
|
||||
}
|
||||
void SimRadio::startTransmitTimer(bool withDelay)
|
||||
{
|
||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||
if (!txQueue.empty()) {
|
||||
uint32_t delayMsec = !withDelay ? 1 : getTxDelayMsec();
|
||||
// LOG_DEBUG("xmit timer %d", delay);
|
||||
notifyLater(delayMsec, TRANSMIT_DELAY_COMPLETED, false);
|
||||
}
|
||||
}
|
||||
|
||||
void SimRadio::startTransmitTimerRebroadcast(meshtastic_MeshPacket *p) {
|
||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||
if (!txQueue.empty()) {
|
||||
uint32_t delayMsec = getTxDelayMsecWeighted(p);
|
||||
// LOG_DEBUG("xmit timer %d", delay);
|
||||
notifyLater(delayMsec, TRANSMIT_DELAY_COMPLETED, false);
|
||||
}
|
||||
void SimRadio::startTransmitTimerRebroadcast(meshtastic_MeshPacket *p)
|
||||
{
|
||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||
if (!txQueue.empty()) {
|
||||
uint32_t delayMsec = getTxDelayMsecWeighted(p);
|
||||
// LOG_DEBUG("xmit timer %d", delay);
|
||||
notifyLater(delayMsec, TRANSMIT_DELAY_COMPLETED, false);
|
||||
}
|
||||
}
|
||||
|
||||
void SimRadio::handleTransmitInterrupt() {
|
||||
// This can be null if we forced the device to enter standby mode. In that case
|
||||
// ignore the transmit interrupt
|
||||
if (sendingPacket)
|
||||
completeSending();
|
||||
void SimRadio::handleTransmitInterrupt()
|
||||
{
|
||||
// This can be null if we forced the device to enter standby mode. In that case
|
||||
// ignore the transmit interrupt
|
||||
if (sendingPacket)
|
||||
completeSending();
|
||||
|
||||
isReceiving = true;
|
||||
if (receivingPacket) // This happens when we don't consider something a collision if we weren't sending long enough
|
||||
handleReceiveInterrupt();
|
||||
isReceiving = true;
|
||||
if (receivingPacket) // This happens when we don't consider something a collision if we weren't sending long enough
|
||||
handleReceiveInterrupt();
|
||||
}
|
||||
|
||||
void SimRadio::completeSending() {
|
||||
// We are careful to clear sending packet before calling printPacket because
|
||||
// that can take a long time
|
||||
auto p = sendingPacket;
|
||||
sendingPacket = NULL;
|
||||
void SimRadio::completeSending()
|
||||
{
|
||||
// We are careful to clear sending packet before calling printPacket because
|
||||
// that can take a long time
|
||||
auto p = sendingPacket;
|
||||
sendingPacket = NULL;
|
||||
|
||||
if (p) {
|
||||
txGood++;
|
||||
if (!isFromUs(p))
|
||||
txRelay++;
|
||||
printPacket("Completed sending", p);
|
||||
if (p) {
|
||||
txGood++;
|
||||
if (!isFromUs(p))
|
||||
txRelay++;
|
||||
printPacket("Completed sending", p);
|
||||
|
||||
// We are done sending that packet, release it
|
||||
packetPool.release(p);
|
||||
// LOG_DEBUG("Done with send");
|
||||
}
|
||||
// We are done sending that packet, release it
|
||||
packetPool.release(p);
|
||||
// LOG_DEBUG("Done with send");
|
||||
}
|
||||
}
|
||||
|
||||
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
||||
bool SimRadio::canSendImmediately() {
|
||||
// We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one).
|
||||
// To do otherwise would be doubly bad because not only would we drop the packet that was on the way in,
|
||||
// we almost certainly guarantee no one outside will like the packet we are sending.
|
||||
bool busyTx = sendingPacket != NULL;
|
||||
bool busyRx = isReceiving && isActivelyReceiving();
|
||||
bool SimRadio::canSendImmediately()
|
||||
{
|
||||
// We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one).
|
||||
// To do otherwise would be doubly bad because not only would we drop the packet that was on the way in,
|
||||
// we almost certainly guarantee no one outside will like the packet we are sending.
|
||||
bool busyTx = sendingPacket != NULL;
|
||||
bool busyRx = isReceiving && isActivelyReceiving();
|
||||
|
||||
if (busyTx || busyRx) {
|
||||
if (busyTx)
|
||||
LOG_WARN("Can not send yet, busyTx");
|
||||
if (busyRx)
|
||||
LOG_WARN("Can not send yet, busyRx");
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
if (busyTx || busyRx) {
|
||||
if (busyTx)
|
||||
LOG_WARN("Can not send yet, busyTx");
|
||||
if (busyRx)
|
||||
LOG_WARN("Can not send yet, busyRx");
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SimRadio::isActivelyReceiving() { return receivingPacket != nullptr; }
|
||||
bool SimRadio::isActivelyReceiving()
|
||||
{
|
||||
return receivingPacket != nullptr;
|
||||
}
|
||||
|
||||
bool SimRadio::isChannelActive() { return receivingPacket != nullptr; }
|
||||
bool SimRadio::isChannelActive()
|
||||
{
|
||||
return receivingPacket != nullptr;
|
||||
}
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
bool SimRadio::cancelSending(NodeNum from, PacketId id) {
|
||||
auto p = txQueue.remove(from, id);
|
||||
if (p)
|
||||
packetPool.release(p); // free the packet we just removed
|
||||
bool SimRadio::cancelSending(NodeNum from, PacketId id)
|
||||
{
|
||||
auto p = txQueue.remove(from, id);
|
||||
if (p)
|
||||
packetPool.release(p); // free the packet we just removed
|
||||
|
||||
bool result = (p != NULL);
|
||||
LOG_DEBUG("cancelSending id=0x%x, removed=%d", id, result);
|
||||
return result;
|
||||
bool result = (p != NULL);
|
||||
LOG_DEBUG("cancelSending id=0x%x, removed=%d", id, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */
|
||||
bool SimRadio::findInTxQueue(NodeNum from, PacketId id) { return txQueue.find(from, id); }
|
||||
bool SimRadio::findInTxQueue(NodeNum from, PacketId id)
|
||||
{
|
||||
return txQueue.find(from, id);
|
||||
}
|
||||
|
||||
void SimRadio::onNotify(uint32_t notification) {
|
||||
switch (notification) {
|
||||
case ISR_TX:
|
||||
handleTransmitInterrupt();
|
||||
// LOG_DEBUG("tx complete - starting timer");
|
||||
startTransmitTimer();
|
||||
break;
|
||||
case ISR_RX:
|
||||
handleReceiveInterrupt();
|
||||
// LOG_DEBUG("rx complete - starting timer");
|
||||
startTransmitTimer();
|
||||
break;
|
||||
case TRANSMIT_DELAY_COMPLETED:
|
||||
if (receivingPacket) { // This happens when we had a timer pending and we started receiving
|
||||
handleReceiveInterrupt();
|
||||
startTransmitTimer();
|
||||
break;
|
||||
}
|
||||
LOG_DEBUG("delay done");
|
||||
|
||||
// If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
|
||||
// has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
|
||||
if (!txQueue.empty()) {
|
||||
if (!canSendImmediately()) {
|
||||
// LOG_DEBUG("Currently Rx/Tx-ing: set random delay");
|
||||
setTransmitDelay(); // currently Rx/Tx-ing: reset random delay
|
||||
} else {
|
||||
if (isChannelActive()) { // check if there is currently a LoRa packet on the channel
|
||||
// LOG_DEBUG("Channel is active: set random delay");
|
||||
setTransmitDelay(); // reset random delay
|
||||
} else {
|
||||
// Send any outgoing packets we have ready
|
||||
meshtastic_MeshPacket *txp = txQueue.dequeue();
|
||||
assert(txp);
|
||||
startSend(txp);
|
||||
// Packet has been sent, count it toward our TX airtime utilization.
|
||||
uint32_t xmitMsec = RadioInterface::getPacketTime(txp);
|
||||
airTime->logAirtime(TX_LOG, xmitMsec);
|
||||
|
||||
notifyLater(xmitMsec, ISR_TX, false); // Model the time it is busy sending
|
||||
void SimRadio::onNotify(uint32_t notification)
|
||||
{
|
||||
switch (notification) {
|
||||
case ISR_TX:
|
||||
handleTransmitInterrupt();
|
||||
// LOG_DEBUG("tx complete - starting timer");
|
||||
startTransmitTimer();
|
||||
break;
|
||||
case ISR_RX:
|
||||
handleReceiveInterrupt();
|
||||
// LOG_DEBUG("rx complete - starting timer");
|
||||
startTransmitTimer();
|
||||
break;
|
||||
case TRANSMIT_DELAY_COMPLETED:
|
||||
if (receivingPacket) { // This happens when we had a timer pending and we started receiving
|
||||
handleReceiveInterrupt();
|
||||
startTransmitTimer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LOG_DEBUG("done with txqueue");
|
||||
LOG_DEBUG("delay done");
|
||||
|
||||
// If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
|
||||
// has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
|
||||
if (!txQueue.empty()) {
|
||||
if (!canSendImmediately()) {
|
||||
// LOG_DEBUG("Currently Rx/Tx-ing: set random delay");
|
||||
setTransmitDelay(); // currently Rx/Tx-ing: reset random delay
|
||||
} else {
|
||||
if (isChannelActive()) { // check if there is currently a LoRa packet on the channel
|
||||
// LOG_DEBUG("Channel is active: set random delay");
|
||||
setTransmitDelay(); // reset random delay
|
||||
} else {
|
||||
// Send any outgoing packets we have ready
|
||||
meshtastic_MeshPacket *txp = txQueue.dequeue();
|
||||
assert(txp);
|
||||
startSend(txp);
|
||||
// Packet has been sent, count it toward our TX airtime utilization.
|
||||
uint32_t xmitMsec = RadioInterface::getPacketTime(txp);
|
||||
airTime->logAirtime(TX_LOG, xmitMsec);
|
||||
|
||||
notifyLater(xmitMsec, ISR_TX, false); // Model the time it is busy sending
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// LOG_DEBUG("done with txqueue");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0); // We expected to receive a valid notification from the ISR
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0); // We expected to receive a valid notification from the ISR
|
||||
}
|
||||
}
|
||||
|
||||
/** start an immediate transmit */
|
||||
void SimRadio::startSend(meshtastic_MeshPacket *txp) {
|
||||
printPacket("Start low level send", txp);
|
||||
isReceiving = false;
|
||||
size_t numbytes = beginSending(txp);
|
||||
meshtastic_MeshPacket *p = packetPool.allocCopy(*txp);
|
||||
perhapsDecode(p);
|
||||
meshtastic_Compressed c = meshtastic_Compressed_init_default;
|
||||
c.portnum = p->decoded.portnum;
|
||||
// LOG_DEBUG("Send back to simulator with portNum %d", p->decoded.portnum);
|
||||
if (p->decoded.payload.size <= sizeof(c.data.bytes)) {
|
||||
memcpy(&c.data.bytes, p->decoded.payload.bytes, p->decoded.payload.size);
|
||||
c.data.size = p->decoded.payload.size;
|
||||
} else {
|
||||
LOG_WARN("Payload size larger than compressed message allows! Send empty payload");
|
||||
}
|
||||
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_Compressed_msg, &c);
|
||||
p->decoded.portnum = meshtastic_PortNum_SIMULATOR_APP;
|
||||
void SimRadio::startSend(meshtastic_MeshPacket *txp)
|
||||
{
|
||||
printPacket("Start low level send", txp);
|
||||
isReceiving = false;
|
||||
size_t numbytes = beginSending(txp);
|
||||
meshtastic_MeshPacket *p = packetPool.allocCopy(*txp);
|
||||
perhapsDecode(p);
|
||||
meshtastic_Compressed c = meshtastic_Compressed_init_default;
|
||||
c.portnum = p->decoded.portnum;
|
||||
// LOG_DEBUG("Send back to simulator with portNum %d", p->decoded.portnum);
|
||||
if (p->decoded.payload.size <= sizeof(c.data.bytes)) {
|
||||
memcpy(&c.data.bytes, p->decoded.payload.bytes, p->decoded.payload.size);
|
||||
c.data.size = p->decoded.payload.size;
|
||||
} else {
|
||||
LOG_WARN("Payload size larger than compressed message allows! Send empty payload");
|
||||
}
|
||||
p->decoded.payload.size =
|
||||
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_Compressed_msg, &c);
|
||||
p->decoded.portnum = meshtastic_PortNum_SIMULATOR_APP;
|
||||
|
||||
service->sendQueueStatusToPhone(router->getQueueStatus(), 0, p->id);
|
||||
service->sendToPhone(p); // Sending back to simulator
|
||||
service->loop(); // Process the send immediately
|
||||
service->sendQueueStatusToPhone(router->getQueueStatus(), 0, p->id);
|
||||
service->sendToPhone(p); // Sending back to simulator
|
||||
service->loop(); // Process the send immediately
|
||||
}
|
||||
|
||||
// Simulates device received a packet via the LoRa chip
|
||||
void SimRadio::unpackAndReceive(meshtastic_MeshPacket &p) {
|
||||
// Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first
|
||||
meshtastic_Compressed scratch;
|
||||
meshtastic_Compressed *decoded = NULL;
|
||||
if (p.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
p.decoded.payload.size = pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Compressed_msg, &scratch);
|
||||
if (p.decoded.payload.size) {
|
||||
decoded = &scratch;
|
||||
// Extract the original payload and replace
|
||||
memcpy(&p.decoded.payload, &decoded->data, sizeof(decoded->data));
|
||||
// Switch the port from PortNum_SIMULATOR_APP back to the original PortNum
|
||||
p.decoded.portnum = decoded->portnum;
|
||||
} else
|
||||
LOG_ERROR("Error decoding proto for simulator message!");
|
||||
}
|
||||
// Let SimRadio receive as if it did via its LoRa chip
|
||||
startReceive(&p);
|
||||
void SimRadio::unpackAndReceive(meshtastic_MeshPacket &p)
|
||||
{
|
||||
// Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first
|
||||
meshtastic_Compressed scratch;
|
||||
meshtastic_Compressed *decoded = NULL;
|
||||
if (p.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
p.decoded.payload.size =
|
||||
pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Compressed_msg, &scratch);
|
||||
if (p.decoded.payload.size) {
|
||||
decoded = &scratch;
|
||||
// Extract the original payload and replace
|
||||
memcpy(&p.decoded.payload, &decoded->data, sizeof(decoded->data));
|
||||
// Switch the port from PortNum_SIMULATOR_APP back to the original PortNum
|
||||
p.decoded.portnum = decoded->portnum;
|
||||
} else
|
||||
LOG_ERROR("Error decoding proto for simulator message!");
|
||||
}
|
||||
// Let SimRadio receive as if it did via its LoRa chip
|
||||
startReceive(&p);
|
||||
}
|
||||
|
||||
void SimRadio::startReceive(meshtastic_MeshPacket *p) {
|
||||
void SimRadio::startReceive(meshtastic_MeshPacket *p)
|
||||
{
|
||||
#ifdef USERPREFS_SIMRADIO_EMULATE_COLLISIONS
|
||||
if (isActivelyReceiving()) {
|
||||
LOG_WARN("Collision detected, dropping current and previous packet!");
|
||||
rxBad++;
|
||||
airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket, true));
|
||||
packetPool.release(receivingPacket);
|
||||
receivingPacket = nullptr;
|
||||
return;
|
||||
} else if (sendingPacket) {
|
||||
uint32_t airtimeLeft = tillRun(millis());
|
||||
if (airtimeLeft <= 0) {
|
||||
LOG_WARN("Transmitting packet was already done");
|
||||
handleTransmitInterrupt(); // Finish sending first
|
||||
} else if ((interval - airtimeLeft) > preambleTimeMsec) {
|
||||
// Only if transmitting for longer than preamble there is a collision
|
||||
// (channel should actually be detected as active otherwise)
|
||||
LOG_WARN("Collision detected during transmission!");
|
||||
return;
|
||||
if (isActivelyReceiving()) {
|
||||
LOG_WARN("Collision detected, dropping current and previous packet!");
|
||||
rxBad++;
|
||||
airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket, true));
|
||||
packetPool.release(receivingPacket);
|
||||
receivingPacket = nullptr;
|
||||
return;
|
||||
} else if (sendingPacket) {
|
||||
uint32_t airtimeLeft = tillRun(millis());
|
||||
if (airtimeLeft <= 0) {
|
||||
LOG_WARN("Transmitting packet was already done");
|
||||
handleTransmitInterrupt(); // Finish sending first
|
||||
} else if ((interval - airtimeLeft) > preambleTimeMsec) {
|
||||
// Only if transmitting for longer than preamble there is a collision
|
||||
// (channel should actually be detected as active otherwise)
|
||||
LOG_WARN("Collision detected during transmission!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
isReceiving = true;
|
||||
receivingPacket = packetPool.allocCopy(*p);
|
||||
uint32_t airtimeMsec = getPacketTime(p, true);
|
||||
notifyLater(airtimeMsec, ISR_RX, false); // Model the time it is busy receiving
|
||||
isReceiving = true;
|
||||
receivingPacket = packetPool.allocCopy(*p);
|
||||
uint32_t airtimeMsec = getPacketTime(p, true);
|
||||
notifyLater(airtimeMsec, ISR_RX, false); // Model the time it is busy receiving
|
||||
#else
|
||||
isReceiving = true;
|
||||
receivingPacket = packetPool.allocCopy(*p);
|
||||
handleReceiveInterrupt(); // Simulate receiving the packet immediately
|
||||
startTransmitTimer();
|
||||
isReceiving = true;
|
||||
receivingPacket = packetPool.allocCopy(*p);
|
||||
handleReceiveInterrupt(); // Simulate receiving the packet immediately
|
||||
startTransmitTimer();
|
||||
#endif
|
||||
}
|
||||
|
||||
meshtastic_QueueStatus SimRadio::getQueueStatus() {
|
||||
meshtastic_QueueStatus qs;
|
||||
meshtastic_QueueStatus SimRadio::getQueueStatus()
|
||||
{
|
||||
meshtastic_QueueStatus qs;
|
||||
|
||||
qs.res = qs.mesh_packet_id = 0;
|
||||
qs.free = txQueue.getFree();
|
||||
qs.maxlen = txQueue.getMaxLen();
|
||||
qs.res = qs.mesh_packet_id = 0;
|
||||
qs.free = txQueue.getFree();
|
||||
qs.maxlen = txQueue.getMaxLen();
|
||||
|
||||
return qs;
|
||||
return qs;
|
||||
}
|
||||
|
||||
void SimRadio::handleReceiveInterrupt() {
|
||||
if (receivingPacket == nullptr) {
|
||||
return;
|
||||
}
|
||||
void SimRadio::handleReceiveInterrupt()
|
||||
{
|
||||
if (receivingPacket == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isReceiving) {
|
||||
LOG_DEBUG("*** WAS_ASSERT *** handleReceiveInterrupt called when not in receive mode");
|
||||
return;
|
||||
}
|
||||
if (!isReceiving) {
|
||||
LOG_DEBUG("*** WAS_ASSERT *** handleReceiveInterrupt called when not in receive mode");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("HANDLE RECEIVE INTERRUPT");
|
||||
rxGood++;
|
||||
LOG_DEBUG("HANDLE RECEIVE INTERRUPT");
|
||||
rxGood++;
|
||||
|
||||
meshtastic_MeshPacket *mp = packetPool.allocCopy(*receivingPacket); // keep a copy in packetPool
|
||||
packetPool.release(receivingPacket); // release the original
|
||||
receivingPacket = nullptr;
|
||||
meshtastic_MeshPacket *mp = packetPool.allocCopy(*receivingPacket); // keep a copy in packetPool
|
||||
packetPool.release(receivingPacket); // release the original
|
||||
receivingPacket = nullptr;
|
||||
|
||||
printPacket("Lora RX", mp);
|
||||
printPacket("Lora RX", mp);
|
||||
|
||||
airTime->logAirtime(RX_LOG, RadioInterface::getPacketTime(mp, true));
|
||||
airTime->logAirtime(RX_LOG, RadioInterface::getPacketTime(mp, true));
|
||||
|
||||
deliverToReceiver(mp);
|
||||
deliverToReceiver(mp);
|
||||
}
|
||||
|
||||
size_t SimRadio::getPacketLength(meshtastic_MeshPacket *mp) {
|
||||
auto &p = mp->decoded;
|
||||
return (size_t)p.payload.size + sizeof(PacketHeader);
|
||||
size_t SimRadio::getPacketLength(meshtastic_MeshPacket *mp)
|
||||
{
|
||||
auto &p = mp->decoded;
|
||||
return (size_t)p.payload.size + sizeof(PacketHeader);
|
||||
}
|
||||
|
||||
int16_t SimRadio::readData(uint8_t *data, size_t len) {
|
||||
int16_t state = RADIOLIB_ERR_NONE;
|
||||
int16_t SimRadio::readData(uint8_t *data, size_t len)
|
||||
{
|
||||
int16_t state = RADIOLIB_ERR_NONE;
|
||||
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
// add null terminator
|
||||
data[len] = 0;
|
||||
}
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
// add null terminator
|
||||
data[len] = 0;
|
||||
}
|
||||
|
||||
return state;
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -316,18 +346,20 @@ int16_t SimRadio::readData(uint8_t *data, size_t len) {
|
||||
*
|
||||
* @return num msecs for the packet
|
||||
*/
|
||||
uint32_t SimRadio::getPacketTime(uint32_t pl, bool received) {
|
||||
float bandwidthHz = bw * 1000.0f;
|
||||
bool headDisable = false; // we currently always use the header
|
||||
float tSym = (1 << sf) / bandwidthHz;
|
||||
uint32_t SimRadio::getPacketTime(uint32_t pl, bool received)
|
||||
{
|
||||
float bandwidthHz = bw * 1000.0f;
|
||||
bool headDisable = false; // we currently always use the header
|
||||
float tSym = (1 << sf) / bandwidthHz;
|
||||
|
||||
bool lowDataOptEn = tSym > 16e-3 ? true : false; // Needed if symbol time is >16ms
|
||||
bool lowDataOptEn = tSym > 16e-3 ? true : false; // Needed if symbol time is >16ms
|
||||
|
||||
float tPreamble = (preambleLength + 4.25f) * tSym;
|
||||
float numPayloadSym = 8 + max(ceilf(((8.0f * pl - 4 * sf + 28 + 16 - 20 * headDisable) / (4 * (sf - 2 * lowDataOptEn))) * cr), 0.0f);
|
||||
float tPayload = numPayloadSym * tSym;
|
||||
float tPacket = tPreamble + tPayload;
|
||||
float tPreamble = (preambleLength + 4.25f) * tSym;
|
||||
float numPayloadSym =
|
||||
8 + max(ceilf(((8.0f * pl - 4 * sf + 28 + 16 - 20 * headDisable) / (4 * (sf - 2 * lowDataOptEn))) * cr), 0.0f);
|
||||
float tPayload = numPayloadSym * tSym;
|
||||
float tPacket = tPreamble + tPayload;
|
||||
|
||||
uint32_t msecs = tPacket * 1000;
|
||||
return msecs;
|
||||
uint32_t msecs = tPacket * 1000;
|
||||
return msecs;
|
||||
}
|
||||
@@ -7,89 +7,90 @@
|
||||
|
||||
#include <RadioLib.h>
|
||||
|
||||
class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThread {
|
||||
enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED };
|
||||
class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThread
|
||||
{
|
||||
enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED };
|
||||
|
||||
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
|
||||
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
|
||||
|
||||
public:
|
||||
SimRadio();
|
||||
public:
|
||||
SimRadio();
|
||||
|
||||
/** MeshService needs this to find our active instance
|
||||
*/
|
||||
static SimRadio *instance;
|
||||
/** MeshService needs this to find our active instance
|
||||
*/
|
||||
static SimRadio *instance;
|
||||
|
||||
virtual ErrorCode send(meshtastic_MeshPacket *p) override;
|
||||
virtual ErrorCode send(meshtastic_MeshPacket *p) override;
|
||||
|
||||
/** can we detect a LoRa preamble on the current channel? */
|
||||
virtual bool isChannelActive();
|
||||
/** can we detect a LoRa preamble on the current channel? */
|
||||
virtual bool isChannelActive();
|
||||
|
||||
/** are we actively receiving a packet (only called during receiving state)
|
||||
* This method is only public to facilitate debugging. Do not call.
|
||||
*/
|
||||
virtual bool isActivelyReceiving();
|
||||
/** are we actively receiving a packet (only called during receiving state)
|
||||
* This method is only public to facilitate debugging. Do not call.
|
||||
*/
|
||||
virtual bool isActivelyReceiving();
|
||||
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
virtual bool cancelSending(NodeNum from, PacketId id) override;
|
||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||
virtual bool cancelSending(NodeNum from, PacketId id) override;
|
||||
|
||||
/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */
|
||||
virtual bool findInTxQueue(NodeNum from, PacketId id) override;
|
||||
/** Attempt to find a packet in the TxQueue. Returns true if the packet was found. */
|
||||
virtual bool findInTxQueue(NodeNum from, PacketId id) override;
|
||||
|
||||
/**
|
||||
* Start waiting to receive a message
|
||||
*
|
||||
* External functions can call this method to wake the device from sleep.
|
||||
*/
|
||||
virtual void startReceive(meshtastic_MeshPacket *p);
|
||||
/**
|
||||
* Start waiting to receive a message
|
||||
*
|
||||
* External functions can call this method to wake the device from sleep.
|
||||
*/
|
||||
virtual void startReceive(meshtastic_MeshPacket *p);
|
||||
|
||||
meshtastic_QueueStatus getQueueStatus() override;
|
||||
meshtastic_QueueStatus getQueueStatus() override;
|
||||
|
||||
// Convert Compressed_msg to normal msg and receive it
|
||||
void unpackAndReceive(meshtastic_MeshPacket &p);
|
||||
// Convert Compressed_msg to normal msg and receive it
|
||||
void unpackAndReceive(meshtastic_MeshPacket &p);
|
||||
|
||||
/**
|
||||
* Debugging counts
|
||||
*/
|
||||
uint32_t rxBad = 0, rxGood = 0, txGood = 0, txRelay = 0;
|
||||
uint16_t txDrop = 0;
|
||||
/**
|
||||
* Debugging counts
|
||||
*/
|
||||
uint32_t rxBad = 0, rxGood = 0, txGood = 0, txRelay = 0;
|
||||
uint16_t txDrop = 0;
|
||||
|
||||
protected:
|
||||
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
|
||||
bool isReceiving = true;
|
||||
protected:
|
||||
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
|
||||
bool isReceiving = true;
|
||||
|
||||
private:
|
||||
void setTransmitDelay();
|
||||
private:
|
||||
void setTransmitDelay();
|
||||
|
||||
/** random timer with certain min. and max. settings */
|
||||
void startTransmitTimer(bool withDelay = true);
|
||||
/** random timer with certain min. and max. settings */
|
||||
void startTransmitTimer(bool withDelay = true);
|
||||
|
||||
/** timer scaled to SNR of to be flooded packet */
|
||||
void startTransmitTimerRebroadcast(meshtastic_MeshPacket *p);
|
||||
/** timer scaled to SNR of to be flooded packet */
|
||||
void startTransmitTimerRebroadcast(meshtastic_MeshPacket *p);
|
||||
|
||||
void handleTransmitInterrupt();
|
||||
void handleReceiveInterrupt();
|
||||
void handleTransmitInterrupt();
|
||||
void handleReceiveInterrupt();
|
||||
|
||||
void onNotify(uint32_t notification);
|
||||
void onNotify(uint32_t notification);
|
||||
|
||||
// start an immediate transmit
|
||||
virtual void startSend(meshtastic_MeshPacket *txp);
|
||||
// start an immediate transmit
|
||||
virtual void startSend(meshtastic_MeshPacket *txp);
|
||||
|
||||
// derive packet length
|
||||
size_t getPacketLength(meshtastic_MeshPacket *p);
|
||||
// derive packet length
|
||||
size_t getPacketLength(meshtastic_MeshPacket *p);
|
||||
|
||||
int16_t readData(uint8_t *str, size_t len);
|
||||
int16_t readData(uint8_t *str, size_t len);
|
||||
|
||||
meshtastic_MeshPacket *receivingPacket = nullptr; // The packet we are currently receiving
|
||||
meshtastic_MeshPacket *receivingPacket = nullptr; // The packet we are currently receiving
|
||||
|
||||
protected:
|
||||
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
||||
virtual bool canSendImmediately();
|
||||
protected:
|
||||
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
||||
virtual bool canSendImmediately();
|
||||
|
||||
/**
|
||||
* If a send was in progress finish it and return the buffer to the pool */
|
||||
void completeSending();
|
||||
/**
|
||||
* If a send was in progress finish it and return the buffer to the pool */
|
||||
void completeSending();
|
||||
|
||||
virtual uint32_t getPacketTime(uint32_t pl, bool received = false) override;
|
||||
virtual uint32_t getPacketTime(uint32_t pl, bool received = false) override;
|
||||
};
|
||||
|
||||
extern SimRadio *simRadio;
|
||||
+121
-107
@@ -23,132 +23,146 @@
|
||||
|
||||
// the HAL must inherit from the base RadioLibHal class
|
||||
// and implement all of its virtual methods
|
||||
class Ch341Hal : public RadioLibHal {
|
||||
public:
|
||||
// default constructor - initializes the base HAL and any needed private members
|
||||
explicit Ch341Hal(uint8_t spiChannel, std::string serial = "", uint32_t vid = 0x1A86, uint32_t pid = 0x5512, uint32_t spiSpeed = 2000000,
|
||||
uint8_t spiDevice = 0, uint8_t gpioDevice = 0)
|
||||
: RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, PI_RISING, PI_FALLING) {
|
||||
if (serial != "") {
|
||||
strncpy(pinedio.serial_number, serial.c_str(), 8);
|
||||
pinedio_set_option(&pinedio, PINEDIO_OPTION_SEARCH_SERIAL, 1);
|
||||
}
|
||||
// LOG_INFO("USB Serial: %s", pinedio.serial_number);
|
||||
class Ch341Hal : public RadioLibHal
|
||||
{
|
||||
public:
|
||||
// default constructor - initializes the base HAL and any needed private members
|
||||
explicit Ch341Hal(uint8_t spiChannel, std::string serial = "", uint32_t vid = 0x1A86, uint32_t pid = 0x5512,
|
||||
uint32_t spiSpeed = 2000000, uint8_t spiDevice = 0, uint8_t gpioDevice = 0)
|
||||
: RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, PI_RISING, PI_FALLING)
|
||||
{
|
||||
if (serial != "") {
|
||||
strncpy(pinedio.serial_number, serial.c_str(), 8);
|
||||
pinedio_set_option(&pinedio, PINEDIO_OPTION_SEARCH_SERIAL, 1);
|
||||
}
|
||||
// LOG_INFO("USB Serial: %s", pinedio.serial_number);
|
||||
|
||||
// There is no vendor with 0x0 -> so check
|
||||
if (vid != 0x0) {
|
||||
pinedio_set_option(&pinedio, PINEDIO_OPTION_VID, vid);
|
||||
pinedio_set_option(&pinedio, PINEDIO_OPTION_PID, pid);
|
||||
}
|
||||
int32_t ret = pinedio_init(&pinedio, NULL);
|
||||
if (ret != 0) {
|
||||
std::string s = "Could not open SPI: ";
|
||||
throw(s + std::to_string(ret));
|
||||
// There is no vendor with 0x0 -> so check
|
||||
if (vid != 0x0) {
|
||||
pinedio_set_option(&pinedio, PINEDIO_OPTION_VID, vid);
|
||||
pinedio_set_option(&pinedio, PINEDIO_OPTION_PID, pid);
|
||||
}
|
||||
int32_t ret = pinedio_init(&pinedio, NULL);
|
||||
if (ret != 0) {
|
||||
std::string s = "Could not open SPI: ";
|
||||
throw(s + std::to_string(ret));
|
||||
}
|
||||
|
||||
pinedio_set_option(&pinedio, PINEDIO_OPTION_AUTO_CS, 0);
|
||||
pinedio_set_pin_mode(&pinedio, 3, true);
|
||||
pinedio_set_pin_mode(&pinedio, 5, true);
|
||||
}
|
||||
|
||||
pinedio_set_option(&pinedio, PINEDIO_OPTION_AUTO_CS, 0);
|
||||
pinedio_set_pin_mode(&pinedio, 3, true);
|
||||
pinedio_set_pin_mode(&pinedio, 5, true);
|
||||
}
|
||||
~Ch341Hal() { pinedio_deinit(&pinedio); }
|
||||
|
||||
~Ch341Hal() { pinedio_deinit(&pinedio); }
|
||||
|
||||
void getSerialString(char *_serial, size_t len) {
|
||||
len = len > 8 ? 8 : len;
|
||||
strncpy(_serial, pinedio.serial_number, len);
|
||||
}
|
||||
|
||||
void getProductString(char *_product_string, size_t len) {
|
||||
len = len > 95 ? 95 : len;
|
||||
strncpy(_product_string, pinedio.product_string, len);
|
||||
}
|
||||
|
||||
void init() override {}
|
||||
void term() override {}
|
||||
|
||||
// GPIO-related methods (pinMode, digitalWrite etc.) should check
|
||||
// RADIOLIB_NC as an alias for non-connected pins
|
||||
void pinMode(uint32_t pin, uint32_t mode) override {
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return;
|
||||
void getSerialString(char *_serial, size_t len)
|
||||
{
|
||||
len = len > 8 ? 8 : len;
|
||||
strncpy(_serial, pinedio.serial_number, len);
|
||||
}
|
||||
pinedio_set_pin_mode(&pinedio, pin, mode);
|
||||
}
|
||||
|
||||
void digitalWrite(uint32_t pin, uint32_t value) override {
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return;
|
||||
void getProductString(char *_product_string, size_t len)
|
||||
{
|
||||
len = len > 95 ? 95 : len;
|
||||
strncpy(_product_string, pinedio.product_string, len);
|
||||
}
|
||||
pinedio_digital_write(&pinedio, pin, value);
|
||||
}
|
||||
|
||||
uint32_t digitalRead(uint32_t pin) override {
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return 0;
|
||||
void init() override {}
|
||||
void term() override {}
|
||||
|
||||
// GPIO-related methods (pinMode, digitalWrite etc.) should check
|
||||
// RADIOLIB_NC as an alias for non-connected pins
|
||||
void pinMode(uint32_t pin, uint32_t mode) override
|
||||
{
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
pinedio_set_pin_mode(&pinedio, pin, mode);
|
||||
}
|
||||
return pinedio_digital_read(&pinedio, pin);
|
||||
}
|
||||
|
||||
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override {
|
||||
if (interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
void digitalWrite(uint32_t pin, uint32_t value) override
|
||||
{
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
pinedio_digital_write(&pinedio, pin, value);
|
||||
}
|
||||
// LOG_DEBUG("Attach interrupt to pin %d", interruptNum);
|
||||
pinedio_attach_interrupt(&this->pinedio, (pinedio_int_pin)interruptNum, (pinedio_int_mode)mode, interruptCb);
|
||||
}
|
||||
|
||||
void detachInterrupt(uint32_t interruptNum) override {
|
||||
if (interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
uint32_t digitalRead(uint32_t pin) override
|
||||
{
|
||||
if (pin == RADIOLIB_NC) {
|
||||
return 0;
|
||||
}
|
||||
return pinedio_digital_read(&pinedio, pin);
|
||||
}
|
||||
// LOG_DEBUG("Detach interrupt from pin %d", interruptNum);
|
||||
pinedio_deattach_interrupt(&this->pinedio, (pinedio_int_pin)interruptNum);
|
||||
}
|
||||
|
||||
void delay(unsigned long ms) override { delayMicroseconds(ms * 1000); }
|
||||
|
||||
void delayMicroseconds(unsigned long us) override {
|
||||
if (us == 0) {
|
||||
sched_yield();
|
||||
return;
|
||||
void attachInterrupt(uint32_t interruptNum, void (*interruptCb)(void), uint32_t mode) override
|
||||
{
|
||||
if (interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
// LOG_DEBUG("Attach interrupt to pin %d", interruptNum);
|
||||
pinedio_attach_interrupt(&this->pinedio, (pinedio_int_pin)interruptNum, (pinedio_int_mode)mode, interruptCb);
|
||||
}
|
||||
usleep(us);
|
||||
}
|
||||
|
||||
void yield() override { sched_yield(); }
|
||||
|
||||
unsigned long millis() override {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000ULL);
|
||||
}
|
||||
|
||||
unsigned long micros() override {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
|
||||
}
|
||||
|
||||
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override {
|
||||
std::cerr << "pulseIn for pin " << pin << "is not supported!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spiBegin() {}
|
||||
void spiBeginTransaction() {}
|
||||
|
||||
void spiTransfer(uint8_t *out, size_t len, uint8_t *in) {
|
||||
int32_t ret = pinedio_transceive(&this->pinedio, out, in, len);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Could not perform SPI transfer: " << ret << std::endl;
|
||||
void detachInterrupt(uint32_t interruptNum) override
|
||||
{
|
||||
if (interruptNum == RADIOLIB_NC) {
|
||||
return;
|
||||
}
|
||||
// LOG_DEBUG("Detach interrupt from pin %d", interruptNum);
|
||||
pinedio_deattach_interrupt(&this->pinedio, (pinedio_int_pin)interruptNum);
|
||||
}
|
||||
}
|
||||
|
||||
void spiEndTransaction() {}
|
||||
void spiEnd() {}
|
||||
void delay(unsigned long ms) override { delayMicroseconds(ms * 1000); }
|
||||
|
||||
private:
|
||||
pinedio_inst pinedio = {0};
|
||||
void delayMicroseconds(unsigned long us) override
|
||||
{
|
||||
if (us == 0) {
|
||||
sched_yield();
|
||||
return;
|
||||
}
|
||||
usleep(us);
|
||||
}
|
||||
|
||||
void yield() override { sched_yield(); }
|
||||
|
||||
unsigned long millis() override
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000ULL);
|
||||
}
|
||||
|
||||
unsigned long micros() override
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
|
||||
}
|
||||
|
||||
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override
|
||||
{
|
||||
std::cerr << "pulseIn for pin " << pin << "is not supported!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spiBegin() {}
|
||||
void spiBeginTransaction() {}
|
||||
|
||||
void spiTransfer(uint8_t *out, size_t len, uint8_t *in)
|
||||
{
|
||||
int32_t ret = pinedio_transceive(&this->pinedio, out, in, len);
|
||||
if (ret < 0) {
|
||||
std::cerr << "Could not perform SPI transfer: " << ret << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void spiEndTransaction() {}
|
||||
void spiEnd() {}
|
||||
|
||||
private:
|
||||
pinedio_inst pinedio = {0};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,11 +19,11 @@ extern "C" {
|
||||
*
|
||||
* Ring Oscillator (ROSC) API
|
||||
*
|
||||
* A Ring Oscillator is an on-chip oscillator that requires no external crystal. Instead, the output is generated from a
|
||||
* series of inverters that are chained together to create a feedback loop. RP2040 boots from the ring oscillator
|
||||
* initially, meaning the first stages of the bootrom, including booting from SPI flash, will be clocked by the ring
|
||||
* oscillator. If your design has a crystal oscillator, you’ll likely want to switch to this as your reference clock as
|
||||
* soon as possible, because the frequency is more accurate than the ring oscillator.
|
||||
* A Ring Oscillator is an on-chip oscillator that requires no external crystal. Instead, the output is generated from a series of
|
||||
* inverters that are chained together to create a feedback loop. RP2040 boots from the ring oscillator initially, meaning the
|
||||
* first stages of the bootrom, including booting from SPI flash, will be clocked by the ring oscillator. If your design has a
|
||||
* crystal oscillator, you’ll likely want to switch to this as your reference clock as soon as possible, because the frequency is
|
||||
* more accurate than the ring oscillator.
|
||||
*/
|
||||
|
||||
/*! \brief Set frequency of the Ring Oscillator
|
||||
@@ -68,15 +68,22 @@ uint rosc_find_freq(uint32_t low_mhz, uint32_t high_mhz);
|
||||
|
||||
void rosc_set_div(uint32_t div);
|
||||
|
||||
inline static void rosc_clear_bad_write(void) { hw_clear_bits(&rosc_hw->status, ROSC_STATUS_BADWRITE_BITS); }
|
||||
inline static void rosc_clear_bad_write(void)
|
||||
{
|
||||
hw_clear_bits(&rosc_hw->status, ROSC_STATUS_BADWRITE_BITS);
|
||||
}
|
||||
|
||||
inline static bool rosc_write_okay(void) { return !(rosc_hw->status & ROSC_STATUS_BADWRITE_BITS); }
|
||||
inline static bool rosc_write_okay(void)
|
||||
{
|
||||
return !(rosc_hw->status & ROSC_STATUS_BADWRITE_BITS);
|
||||
}
|
||||
|
||||
inline static void rosc_write(io_rw_32 *addr, uint32_t value) {
|
||||
rosc_clear_bad_write();
|
||||
assert(rosc_write_okay());
|
||||
*addr = value;
|
||||
assert(rosc_write_okay());
|
||||
inline static void rosc_write(io_rw_32 *addr, uint32_t value)
|
||||
{
|
||||
rosc_clear_bad_write();
|
||||
assert(rosc_write_okay());
|
||||
*addr = value;
|
||||
assert(rosc_write_okay());
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -12,50 +12,59 @@
|
||||
|
||||
// Given a ROSC delay stage code, return the next-numerically-higher code.
|
||||
// Top result bit is set when called on maximum ROSC code.
|
||||
uint32_t next_rosc_code(uint32_t code) { return ((code | 0x08888888u) + 1u) & 0xf7777777u; }
|
||||
uint32_t next_rosc_code(uint32_t code)
|
||||
{
|
||||
return ((code | 0x08888888u) + 1u) & 0xf7777777u;
|
||||
}
|
||||
|
||||
uint rosc_find_freq(uint32_t low_mhz, uint32_t high_mhz) {
|
||||
// TODO: This could be a lot better
|
||||
rosc_set_div(1);
|
||||
for (uint32_t code = 0; code <= 0x77777777u; code = next_rosc_code(code)) {
|
||||
rosc_set_freq(code);
|
||||
uint rosc_mhz = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC) / 1000;
|
||||
if ((rosc_mhz >= low_mhz) && (rosc_mhz <= high_mhz)) {
|
||||
return rosc_mhz;
|
||||
uint rosc_find_freq(uint32_t low_mhz, uint32_t high_mhz)
|
||||
{
|
||||
// TODO: This could be a lot better
|
||||
rosc_set_div(1);
|
||||
for (uint32_t code = 0; code <= 0x77777777u; code = next_rosc_code(code)) {
|
||||
rosc_set_freq(code);
|
||||
uint rosc_mhz = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC) / 1000;
|
||||
if ((rosc_mhz >= low_mhz) && (rosc_mhz <= high_mhz)) {
|
||||
return rosc_mhz;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rosc_set_div(uint32_t div) {
|
||||
assert(div <= 31 && div >= 1);
|
||||
rosc_write(&rosc_hw->div, ROSC_DIV_VALUE_PASS + div);
|
||||
void rosc_set_div(uint32_t div)
|
||||
{
|
||||
assert(div <= 31 && div >= 1);
|
||||
rosc_write(&rosc_hw->div, ROSC_DIV_VALUE_PASS + div);
|
||||
}
|
||||
|
||||
void rosc_set_freq(uint32_t code) {
|
||||
rosc_write(&rosc_hw->freqa, (ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) | (code & 0xffffu));
|
||||
rosc_write(&rosc_hw->freqb, (ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) | (code >> 16u));
|
||||
void rosc_set_freq(uint32_t code)
|
||||
{
|
||||
rosc_write(&rosc_hw->freqa, (ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) | (code & 0xffffu));
|
||||
rosc_write(&rosc_hw->freqb, (ROSC_FREQA_PASSWD_VALUE_PASS << ROSC_FREQA_PASSWD_LSB) | (code >> 16u));
|
||||
}
|
||||
|
||||
void rosc_set_range(uint range) {
|
||||
// Range should use enumvals from the headers and thus have the password correct
|
||||
rosc_write(&rosc_hw->ctrl, (ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB) | range);
|
||||
void rosc_set_range(uint range)
|
||||
{
|
||||
// Range should use enumvals from the headers and thus have the password correct
|
||||
rosc_write(&rosc_hw->ctrl, (ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB) | range);
|
||||
}
|
||||
|
||||
void rosc_disable(void) {
|
||||
uint32_t tmp = rosc_hw->ctrl;
|
||||
tmp &= (~ROSC_CTRL_ENABLE_BITS);
|
||||
tmp |= (ROSC_CTRL_ENABLE_VALUE_DISABLE << ROSC_CTRL_ENABLE_LSB);
|
||||
rosc_write(&rosc_hw->ctrl, tmp);
|
||||
// Wait for stable to go away
|
||||
while (rosc_hw->status & ROSC_STATUS_STABLE_BITS)
|
||||
;
|
||||
void rosc_disable(void)
|
||||
{
|
||||
uint32_t tmp = rosc_hw->ctrl;
|
||||
tmp &= (~ROSC_CTRL_ENABLE_BITS);
|
||||
tmp |= (ROSC_CTRL_ENABLE_VALUE_DISABLE << ROSC_CTRL_ENABLE_LSB);
|
||||
rosc_write(&rosc_hw->ctrl, tmp);
|
||||
// Wait for stable to go away
|
||||
while (rosc_hw->status & ROSC_STATUS_STABLE_BITS)
|
||||
;
|
||||
}
|
||||
|
||||
void rosc_set_dormant(void) {
|
||||
// WARNING: This stops the rosc until woken up by an irq
|
||||
rosc_write(&rosc_hw->dormant, ROSC_DORMANT_VALUE_DORMANT);
|
||||
// Wait for it to become stable once woken up
|
||||
while (!(rosc_hw->status & ROSC_STATUS_STABLE_BITS))
|
||||
;
|
||||
void rosc_set_dormant(void)
|
||||
{
|
||||
// WARNING: This stops the rosc until woken up by an irq
|
||||
rosc_write(&rosc_hw->dormant, ROSC_DORMANT_VALUE_DORMANT);
|
||||
// Wait for it to become stable once woken up
|
||||
while (!(rosc_hw->status & ROSC_STATUS_STABLE_BITS))
|
||||
;
|
||||
}
|
||||
@@ -10,133 +10,148 @@
|
||||
|
||||
static bool awake;
|
||||
|
||||
static void sleep_callback(void) { awake = true; }
|
||||
|
||||
void epoch_to_datetime(time_t epoch, datetime_t *dt) {
|
||||
struct tm *tm_info;
|
||||
|
||||
tm_info = gmtime(&epoch);
|
||||
dt->year = tm_info->tm_year;
|
||||
dt->month = tm_info->tm_mon + 1;
|
||||
dt->day = tm_info->tm_mday;
|
||||
dt->dotw = tm_info->tm_wday;
|
||||
dt->hour = tm_info->tm_hour;
|
||||
dt->min = tm_info->tm_min;
|
||||
dt->sec = tm_info->tm_sec;
|
||||
static void sleep_callback(void)
|
||||
{
|
||||
awake = true;
|
||||
}
|
||||
|
||||
void debug_date(datetime_t t) {
|
||||
LOG_DEBUG("%d %d %d %d %d %d %d", t.year, t.month, t.day, t.hour, t.min, t.sec, t.dotw);
|
||||
uart_default_tx_wait_blocking();
|
||||
void epoch_to_datetime(time_t epoch, datetime_t *dt)
|
||||
{
|
||||
struct tm *tm_info;
|
||||
|
||||
tm_info = gmtime(&epoch);
|
||||
dt->year = tm_info->tm_year;
|
||||
dt->month = tm_info->tm_mon + 1;
|
||||
dt->day = tm_info->tm_mday;
|
||||
dt->dotw = tm_info->tm_wday;
|
||||
dt->hour = tm_info->tm_hour;
|
||||
dt->min = tm_info->tm_min;
|
||||
dt->sec = tm_info->tm_sec;
|
||||
}
|
||||
|
||||
void cpuDeepSleep(uint32_t msecs) {
|
||||
void debug_date(datetime_t t)
|
||||
{
|
||||
LOG_DEBUG("%d %d %d %d %d %d %d", t.year, t.month, t.day, t.hour, t.min, t.sec, t.dotw);
|
||||
uart_default_tx_wait_blocking();
|
||||
}
|
||||
|
||||
time_t seconds = (time_t)(msecs / 1000);
|
||||
datetime_t t_init, t_alarm;
|
||||
void cpuDeepSleep(uint32_t msecs)
|
||||
{
|
||||
|
||||
awake = false;
|
||||
// Start the RTC
|
||||
rtc_init();
|
||||
epoch_to_datetime(0, &t_init);
|
||||
rtc_set_datetime(&t_init);
|
||||
epoch_to_datetime(seconds, &t_alarm);
|
||||
// debug_date(t_init);
|
||||
// debug_date(t_alarm);
|
||||
uart_default_tx_wait_blocking();
|
||||
sleep_run_from_dormant_source(DORMANT_SOURCE_ROSC);
|
||||
sleep_goto_sleep_until(&t_alarm, &sleep_callback);
|
||||
time_t seconds = (time_t)(msecs / 1000);
|
||||
datetime_t t_init, t_alarm;
|
||||
|
||||
// Make sure we don't wake
|
||||
while (!awake) {
|
||||
delay(1);
|
||||
}
|
||||
awake = false;
|
||||
// Start the RTC
|
||||
rtc_init();
|
||||
epoch_to_datetime(0, &t_init);
|
||||
rtc_set_datetime(&t_init);
|
||||
epoch_to_datetime(seconds, &t_alarm);
|
||||
// debug_date(t_init);
|
||||
// debug_date(t_alarm);
|
||||
uart_default_tx_wait_blocking();
|
||||
sleep_run_from_dormant_source(DORMANT_SOURCE_ROSC);
|
||||
sleep_goto_sleep_until(&t_alarm, &sleep_callback);
|
||||
|
||||
/* For now, I don't know how to revert this state
|
||||
We just reboot in order to get back operational */
|
||||
rp2040.reboot();
|
||||
// Make sure we don't wake
|
||||
while (!awake) {
|
||||
delay(1);
|
||||
}
|
||||
|
||||
/* Set RP2040 in dormant mode. Will not wake up. */
|
||||
// xosc_dormant();
|
||||
/* For now, I don't know how to revert this state
|
||||
We just reboot in order to get back operational */
|
||||
rp2040.reboot();
|
||||
|
||||
/* Set RP2040 in dormant mode. Will not wake up. */
|
||||
// xosc_dormant();
|
||||
}
|
||||
|
||||
#else
|
||||
void cpuDeepSleep(uint32_t msecs) {
|
||||
/* Set RP2040 in dormant mode. Will not wake up. */
|
||||
xosc_dormant();
|
||||
void cpuDeepSleep(uint32_t msecs)
|
||||
{
|
||||
/* Set RP2040 in dormant mode. Will not wake up. */
|
||||
xosc_dormant();
|
||||
}
|
||||
#endif
|
||||
|
||||
void setBluetoothEnable(bool enable) {
|
||||
// not needed
|
||||
void setBluetoothEnable(bool enable)
|
||||
{
|
||||
// not needed
|
||||
}
|
||||
|
||||
void updateBatteryLevel(uint8_t level) {
|
||||
// not needed
|
||||
void updateBatteryLevel(uint8_t level)
|
||||
{
|
||||
// not needed
|
||||
}
|
||||
|
||||
void getMacAddr(uint8_t *dmac) {
|
||||
pico_unique_board_id_t src;
|
||||
pico_get_unique_board_id(&src);
|
||||
dmac[5] = src.id[7];
|
||||
dmac[4] = src.id[6];
|
||||
dmac[3] = src.id[5];
|
||||
dmac[2] = src.id[4];
|
||||
dmac[1] = src.id[3];
|
||||
dmac[0] = src.id[2];
|
||||
void getMacAddr(uint8_t *dmac)
|
||||
{
|
||||
pico_unique_board_id_t src;
|
||||
pico_get_unique_board_id(&src);
|
||||
dmac[5] = src.id[7];
|
||||
dmac[4] = src.id[6];
|
||||
dmac[3] = src.id[5];
|
||||
dmac[2] = src.id[4];
|
||||
dmac[1] = src.id[3];
|
||||
dmac[0] = src.id[2];
|
||||
}
|
||||
|
||||
void rp2040Setup() {
|
||||
/* Sets a random seed to make sure we get different random numbers on each boot.
|
||||
Taken from CPU cycle counter and ROSC oscillator, so should be pretty random.
|
||||
*/
|
||||
randomSeed(rp2040.hwrand32());
|
||||
void rp2040Setup()
|
||||
{
|
||||
/* Sets a random seed to make sure we get different random numbers on each boot.
|
||||
Taken from CPU cycle counter and ROSC oscillator, so should be pretty random.
|
||||
*/
|
||||
randomSeed(rp2040.hwrand32());
|
||||
|
||||
#ifdef RP2040_SLOW_CLOCK
|
||||
uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY);
|
||||
uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);
|
||||
uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC);
|
||||
uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);
|
||||
uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI);
|
||||
uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB);
|
||||
uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC);
|
||||
uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);
|
||||
uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY);
|
||||
uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);
|
||||
uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC);
|
||||
uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);
|
||||
uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI);
|
||||
uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB);
|
||||
uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC);
|
||||
uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);
|
||||
|
||||
LOG_INFO("Clock speed:");
|
||||
LOG_INFO("pll_sys = %dkHz", f_pll_sys);
|
||||
LOG_INFO("pll_usb = %dkHz", f_pll_usb);
|
||||
LOG_INFO("rosc = %dkHz", f_rosc);
|
||||
LOG_INFO("clk_sys = %dkHz", f_clk_sys);
|
||||
LOG_INFO("clk_peri = %dkHz", f_clk_peri);
|
||||
LOG_INFO("clk_usb = %dkHz", f_clk_usb);
|
||||
LOG_INFO("clk_adc = %dkHz", f_clk_adc);
|
||||
LOG_INFO("clk_rtc = %dkHz", f_clk_rtc);
|
||||
LOG_INFO("Clock speed:");
|
||||
LOG_INFO("pll_sys = %dkHz", f_pll_sys);
|
||||
LOG_INFO("pll_usb = %dkHz", f_pll_usb);
|
||||
LOG_INFO("rosc = %dkHz", f_rosc);
|
||||
LOG_INFO("clk_sys = %dkHz", f_clk_sys);
|
||||
LOG_INFO("clk_peri = %dkHz", f_clk_peri);
|
||||
LOG_INFO("clk_usb = %dkHz", f_clk_usb);
|
||||
LOG_INFO("clk_adc = %dkHz", f_clk_adc);
|
||||
LOG_INFO("clk_rtc = %dkHz", f_clk_rtc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void enterDfuMode() { reset_usb_boot(0, 0); }
|
||||
void enterDfuMode()
|
||||
{
|
||||
reset_usb_boot(0, 0);
|
||||
}
|
||||
|
||||
/* Init in early boot state. */
|
||||
#ifdef RP2040_SLOW_CLOCK
|
||||
void initVariant() {
|
||||
/* Set the system frequency to 18 MHz. */
|
||||
set_sys_clock_khz(18 * KHZ, false);
|
||||
/* The previous line automatically detached clk_peri from clk_sys, and
|
||||
attached it to pll_usb. We need to attach clk_peri back to system PLL to keep SPI
|
||||
working at this low speed.
|
||||
For details see https://github.com/jgromes/RadioLib/discussions/938
|
||||
*/
|
||||
clock_configure(clk_peri,
|
||||
0, // No glitchless mux
|
||||
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, // System PLL on AUX mux
|
||||
18 * MHZ, // Input frequency
|
||||
18 * MHZ // Output (must be same as no divider)
|
||||
);
|
||||
/* Run also ADC on lower clk_sys. */
|
||||
clock_configure(clk_adc, 0, CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, 18 * MHZ, 18 * MHZ);
|
||||
/* Run RTC from XOSC since USB clock is off */
|
||||
clock_configure(clk_rtc, 0, CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC, 12 * MHZ, 47 * KHZ);
|
||||
/* Turn off USB PLL */
|
||||
pll_deinit(pll_usb);
|
||||
void initVariant()
|
||||
{
|
||||
/* Set the system frequency to 18 MHz. */
|
||||
set_sys_clock_khz(18 * KHZ, false);
|
||||
/* The previous line automatically detached clk_peri from clk_sys, and
|
||||
attached it to pll_usb. We need to attach clk_peri back to system PLL to keep SPI
|
||||
working at this low speed.
|
||||
For details see https://github.com/jgromes/RadioLib/discussions/938
|
||||
*/
|
||||
clock_configure(clk_peri,
|
||||
0, // No glitchless mux
|
||||
CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, // System PLL on AUX mux
|
||||
18 * MHZ, // Input frequency
|
||||
18 * MHZ // Output (must be same as no divider)
|
||||
);
|
||||
/* Run also ADC on lower clk_sys. */
|
||||
clock_configure(clk_adc, 0, CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS, 18 * MHZ, 18 * MHZ);
|
||||
/* Run RTC from XOSC since USB clock is off */
|
||||
clock_configure(clk_rtc, 0, CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC, 12 * MHZ, 47 * KHZ);
|
||||
/* Turn off USB PLL */
|
||||
pll_deinit(pll_usb);
|
||||
}
|
||||
#endif
|
||||
@@ -42,12 +42,18 @@ void sleep_run_from_dormant_source(dormant_source_t dormant_source);
|
||||
/*! \brief Set the dormant clock source to be the crystal oscillator
|
||||
* \ingroup hardware_sleep
|
||||
*/
|
||||
static inline void sleep_run_from_xosc(void) { sleep_run_from_dormant_source(DORMANT_SOURCE_XOSC); }
|
||||
static inline void sleep_run_from_xosc(void)
|
||||
{
|
||||
sleep_run_from_dormant_source(DORMANT_SOURCE_XOSC);
|
||||
}
|
||||
|
||||
/*! \brief Set the dormant clock source to be the ring oscillator
|
||||
* \ingroup hardware_sleep
|
||||
*/
|
||||
static inline void sleep_run_from_rosc(void) { sleep_run_from_dormant_source(DORMANT_SOURCE_ROSC); }
|
||||
static inline void sleep_run_from_rosc(void)
|
||||
{
|
||||
sleep_run_from_dormant_source(DORMANT_SOURCE_ROSC);
|
||||
}
|
||||
|
||||
/*! \brief Send system to sleep until the specified time
|
||||
* \ingroup hardware_sleep
|
||||
@@ -77,7 +83,10 @@ void sleep_goto_dormant_until_pin(uint gpio_pin, bool edge, bool high);
|
||||
*
|
||||
* \param gpio_pin The pin to provide the wake up
|
||||
*/
|
||||
static inline void sleep_goto_dormant_until_edge_high(uint gpio_pin) { sleep_goto_dormant_until_pin(gpio_pin, true, true); }
|
||||
static inline void sleep_goto_dormant_until_edge_high(uint gpio_pin)
|
||||
{
|
||||
sleep_goto_dormant_until_pin(gpio_pin, true, true);
|
||||
}
|
||||
|
||||
/*! \brief Send system to sleep until a high level is detected on GPIO
|
||||
* \ingroup hardware_sleep
|
||||
@@ -86,7 +95,10 @@ static inline void sleep_goto_dormant_until_edge_high(uint gpio_pin) { sleep_got
|
||||
*
|
||||
* \param gpio_pin The pin to provide the wake up
|
||||
*/
|
||||
static inline void sleep_goto_dormant_until_level_high(uint gpio_pin) { sleep_goto_dormant_until_pin(gpio_pin, false, true); }
|
||||
static inline void sleep_goto_dormant_until_level_high(uint gpio_pin)
|
||||
{
|
||||
sleep_goto_dormant_until_pin(gpio_pin, false, true);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -33,118 +33,123 @@
|
||||
|
||||
static dormant_source_t _dormant_source;
|
||||
|
||||
bool dormant_source_valid(dormant_source_t dormant_source) {
|
||||
return (dormant_source == DORMANT_SOURCE_XOSC) || (dormant_source == DORMANT_SOURCE_ROSC);
|
||||
bool dormant_source_valid(dormant_source_t dormant_source)
|
||||
{
|
||||
return (dormant_source == DORMANT_SOURCE_XOSC) || (dormant_source == DORMANT_SOURCE_ROSC);
|
||||
}
|
||||
|
||||
// In order to go into dormant mode we need to be running from a stoppable clock source:
|
||||
// either the xosc or rosc with no PLLs running. This means we disable the USB and ADC clocks
|
||||
// and all PLLs
|
||||
void sleep_run_from_dormant_source(dormant_source_t dormant_source) {
|
||||
assert(dormant_source_valid(dormant_source));
|
||||
_dormant_source = dormant_source;
|
||||
void sleep_run_from_dormant_source(dormant_source_t dormant_source)
|
||||
{
|
||||
assert(dormant_source_valid(dormant_source));
|
||||
_dormant_source = dormant_source;
|
||||
|
||||
// FIXME: Just defining average rosc freq here.
|
||||
uint src_hz = (dormant_source == DORMANT_SOURCE_XOSC) ? XOSC_HZ : 6.5 * MHZ;
|
||||
uint clk_ref_src =
|
||||
(dormant_source == DORMANT_SOURCE_XOSC) ? CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC : CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH;
|
||||
// FIXME: Just defining average rosc freq here.
|
||||
uint src_hz = (dormant_source == DORMANT_SOURCE_XOSC) ? XOSC_HZ : 6.5 * MHZ;
|
||||
uint clk_ref_src = (dormant_source == DORMANT_SOURCE_XOSC) ? CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC
|
||||
: CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH;
|
||||
|
||||
// CLK_REF = XOSC or ROSC
|
||||
clock_configure(clk_ref, clk_ref_src,
|
||||
0, // No aux mux
|
||||
src_hz, src_hz);
|
||||
// CLK_REF = XOSC or ROSC
|
||||
clock_configure(clk_ref, clk_ref_src,
|
||||
0, // No aux mux
|
||||
src_hz, src_hz);
|
||||
|
||||
// CLK SYS = CLK_REF
|
||||
clock_configure(clk_sys, CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF,
|
||||
0, // Using glitchless mux
|
||||
src_hz, src_hz);
|
||||
// CLK SYS = CLK_REF
|
||||
clock_configure(clk_sys, CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF,
|
||||
0, // Using glitchless mux
|
||||
src_hz, src_hz);
|
||||
|
||||
// CLK USB = 0MHz
|
||||
clock_stop(clk_usb);
|
||||
// CLK USB = 0MHz
|
||||
clock_stop(clk_usb);
|
||||
|
||||
// CLK ADC = 0MHz
|
||||
clock_stop(clk_adc);
|
||||
// CLK ADC = 0MHz
|
||||
clock_stop(clk_adc);
|
||||
|
||||
// CLK RTC = ideally XOSC (12MHz) / 256 = 46875Hz but could be rosc
|
||||
uint clk_rtc_src =
|
||||
(dormant_source == DORMANT_SOURCE_XOSC) ? CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC : CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH;
|
||||
// CLK RTC = ideally XOSC (12MHz) / 256 = 46875Hz but could be rosc
|
||||
uint clk_rtc_src = (dormant_source == DORMANT_SOURCE_XOSC) ? CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC
|
||||
: CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH;
|
||||
|
||||
clock_configure(clk_rtc,
|
||||
0, // No GLMUX
|
||||
clk_rtc_src, src_hz, 46875);
|
||||
clock_configure(clk_rtc,
|
||||
0, // No GLMUX
|
||||
clk_rtc_src, src_hz, 46875);
|
||||
|
||||
// CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable
|
||||
clock_configure(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, src_hz, src_hz);
|
||||
// CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable
|
||||
clock_configure(clk_peri, 0, CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS, src_hz, src_hz);
|
||||
|
||||
pll_deinit(pll_sys);
|
||||
pll_deinit(pll_usb);
|
||||
pll_deinit(pll_sys);
|
||||
pll_deinit(pll_usb);
|
||||
|
||||
// Assuming both xosc and rosc are running at the moment
|
||||
if (dormant_source == DORMANT_SOURCE_XOSC) {
|
||||
// Can disable rosc
|
||||
rosc_disable();
|
||||
} else {
|
||||
// Can disable xosc
|
||||
xosc_disable();
|
||||
}
|
||||
// Assuming both xosc and rosc are running at the moment
|
||||
if (dormant_source == DORMANT_SOURCE_XOSC) {
|
||||
// Can disable rosc
|
||||
rosc_disable();
|
||||
} else {
|
||||
// Can disable xosc
|
||||
xosc_disable();
|
||||
}
|
||||
|
||||
// Reconfigure uart with new clocks
|
||||
/* This dones not work with our current core */
|
||||
// setup_default_uart();
|
||||
// Reconfigure uart with new clocks
|
||||
/* This dones not work with our current core */
|
||||
// setup_default_uart();
|
||||
}
|
||||
|
||||
// Go to sleep until woken up by the RTC
|
||||
void sleep_goto_sleep_until(datetime_t *t, rtc_callback_t callback) {
|
||||
// We should have already called the sleep_run_from_dormant_source function
|
||||
assert(dormant_source_valid(_dormant_source));
|
||||
void sleep_goto_sleep_until(datetime_t *t, rtc_callback_t callback)
|
||||
{
|
||||
// We should have already called the sleep_run_from_dormant_source function
|
||||
assert(dormant_source_valid(_dormant_source));
|
||||
|
||||
// Turn off all clocks when in sleep mode except for RTC
|
||||
clocks_hw->sleep_en0 = CLOCKS_SLEEP_EN0_CLK_RTC_RTC_BITS;
|
||||
clocks_hw->sleep_en1 = 0x0;
|
||||
// Turn off all clocks when in sleep mode except for RTC
|
||||
clocks_hw->sleep_en0 = CLOCKS_SLEEP_EN0_CLK_RTC_RTC_BITS;
|
||||
clocks_hw->sleep_en1 = 0x0;
|
||||
|
||||
rtc_set_alarm(t, callback);
|
||||
rtc_set_alarm(t, callback);
|
||||
|
||||
uint save = scb_hw->scr;
|
||||
// Enable deep sleep at the proc
|
||||
scb_hw->scr = save | M0PLUS_SCR_SLEEPDEEP_BITS;
|
||||
uint save = scb_hw->scr;
|
||||
// Enable deep sleep at the proc
|
||||
scb_hw->scr = save | M0PLUS_SCR_SLEEPDEEP_BITS;
|
||||
|
||||
// Go to sleep
|
||||
__wfi();
|
||||
// Go to sleep
|
||||
__wfi();
|
||||
}
|
||||
|
||||
static void _go_dormant(void) {
|
||||
assert(dormant_source_valid(_dormant_source));
|
||||
static void _go_dormant(void)
|
||||
{
|
||||
assert(dormant_source_valid(_dormant_source));
|
||||
|
||||
if (_dormant_source == DORMANT_SOURCE_XOSC) {
|
||||
xosc_dormant();
|
||||
} else {
|
||||
rosc_set_dormant();
|
||||
}
|
||||
if (_dormant_source == DORMANT_SOURCE_XOSC) {
|
||||
xosc_dormant();
|
||||
} else {
|
||||
rosc_set_dormant();
|
||||
}
|
||||
}
|
||||
|
||||
void sleep_goto_dormant_until_pin(uint gpio_pin, bool edge, bool high) {
|
||||
bool low = !high;
|
||||
bool level = !edge;
|
||||
void sleep_goto_dormant_until_pin(uint gpio_pin, bool edge, bool high)
|
||||
{
|
||||
bool low = !high;
|
||||
bool level = !edge;
|
||||
|
||||
// Configure the appropriate IRQ at IO bank 0
|
||||
assert(gpio_pin < NUM_BANK0_GPIOS);
|
||||
// Configure the appropriate IRQ at IO bank 0
|
||||
assert(gpio_pin < NUM_BANK0_GPIOS);
|
||||
|
||||
uint32_t event = 0;
|
||||
uint32_t event = 0;
|
||||
|
||||
if (level && low)
|
||||
event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_LEVEL_LOW_BITS;
|
||||
if (level && high)
|
||||
event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_LEVEL_HIGH_BITS;
|
||||
if (edge && high)
|
||||
event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_EDGE_HIGH_BITS;
|
||||
if (edge && low)
|
||||
event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_EDGE_LOW_BITS;
|
||||
if (level && low)
|
||||
event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_LEVEL_LOW_BITS;
|
||||
if (level && high)
|
||||
event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_LEVEL_HIGH_BITS;
|
||||
if (edge && high)
|
||||
event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_EDGE_HIGH_BITS;
|
||||
if (edge && low)
|
||||
event = IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_EDGE_LOW_BITS;
|
||||
|
||||
gpio_set_dormant_irq_enabled(gpio_pin, event, true);
|
||||
gpio_set_dormant_irq_enabled(gpio_pin, event, true);
|
||||
|
||||
_go_dormant();
|
||||
// Execution stops here until woken up
|
||||
_go_dormant();
|
||||
// Execution stops here until woken up
|
||||
|
||||
// Clear the irq so we can go back to dormant mode again if we want
|
||||
gpio_acknowledge_irq(gpio_pin, event);
|
||||
// Clear the irq so we can go back to dormant mode again if we want
|
||||
gpio_acknowledge_irq(gpio_pin, event);
|
||||
}
|
||||
@@ -55,92 +55,96 @@
|
||||
// LFS Disk IO
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static int _internal_flash_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) {
|
||||
LFS_UNUSED(c);
|
||||
static int _internal_flash_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
|
||||
{
|
||||
LFS_UNUSED(c);
|
||||
|
||||
if (!buffer || !size) {
|
||||
_LFS_DBG("%s Invalid parameter!\r\n", __func__);
|
||||
return LFS_ERR_INVAL;
|
||||
}
|
||||
if (!buffer || !size) {
|
||||
_LFS_DBG("%s Invalid parameter!\r\n", __func__);
|
||||
return LFS_ERR_INVAL;
|
||||
}
|
||||
|
||||
lfs_block_t address = LFS_FLASH_ADDR_BASE + (block * STM32WL_PAGE_SIZE + off);
|
||||
lfs_block_t address = LFS_FLASH_ADDR_BASE + (block * STM32WL_PAGE_SIZE + off);
|
||||
|
||||
memcpy(buffer, (void *)address, size);
|
||||
memcpy(buffer, (void *)address, size);
|
||||
|
||||
return LFS_ERR_OK;
|
||||
return LFS_ERR_OK;
|
||||
}
|
||||
|
||||
// Program a region in a block. The block must have previously
|
||||
// been erased. Negative error codes are propogated 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) {
|
||||
lfs_block_t address = LFS_FLASH_ADDR_BASE + (block * STM32WL_PAGE_SIZE + off);
|
||||
HAL_StatusTypeDef hal_rc = HAL_OK;
|
||||
uint32_t dw_count = size / 8;
|
||||
uint64_t *bufp = (uint64_t *)buffer;
|
||||
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)
|
||||
{
|
||||
lfs_block_t address = LFS_FLASH_ADDR_BASE + (block * STM32WL_PAGE_SIZE + off);
|
||||
HAL_StatusTypeDef hal_rc = HAL_OK;
|
||||
uint32_t dw_count = size / 8;
|
||||
uint64_t *bufp = (uint64_t *)buffer;
|
||||
|
||||
LFS_UNUSED(c);
|
||||
LFS_UNUSED(c);
|
||||
|
||||
_LFS_DBG("Programming %d bytes/%d doublewords at address 0x%08x/block %d, offset %d.", size, dw_count, address, block, off);
|
||||
if (HAL_FLASH_Unlock() != HAL_OK) {
|
||||
return LFS_ERR_IO;
|
||||
}
|
||||
for (uint32_t i = 0; i < dw_count; i++) {
|
||||
if ((address < LFS_FLASH_ADDR_BASE) || (address > LFS_FLASH_ADDR_END)) {
|
||||
_LFS_DBG("Wanted to program out of bound of FLASH: 0x%08x.\n", address);
|
||||
HAL_FLASH_Lock();
|
||||
return LFS_ERR_INVAL;
|
||||
_LFS_DBG("Programming %d bytes/%d doublewords at address 0x%08x/block %d, offset %d.", size, dw_count, address, block, off);
|
||||
if (HAL_FLASH_Unlock() != HAL_OK) {
|
||||
return LFS_ERR_IO;
|
||||
}
|
||||
hal_rc = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, *bufp);
|
||||
if (hal_rc != HAL_OK) {
|
||||
/* Error occurred while writing data in Flash memory.
|
||||
* User can add here some code to deal with this error.
|
||||
*/
|
||||
_LFS_DBG("Program error at (0x%08x), 0x%X, error: 0x%08x\n", address, hal_rc, HAL_FLASH_GetError());
|
||||
for (uint32_t i = 0; i < dw_count; i++) {
|
||||
if ((address < LFS_FLASH_ADDR_BASE) || (address > LFS_FLASH_ADDR_END)) {
|
||||
_LFS_DBG("Wanted to program out of bound of FLASH: 0x%08x.\n", address);
|
||||
HAL_FLASH_Lock();
|
||||
return LFS_ERR_INVAL;
|
||||
}
|
||||
hal_rc = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, *bufp);
|
||||
if (hal_rc != HAL_OK) {
|
||||
/* Error occurred while writing data in Flash memory.
|
||||
* User can add here some code to deal with this error.
|
||||
*/
|
||||
_LFS_DBG("Program error at (0x%08x), 0x%X, error: 0x%08x\n", address, hal_rc, HAL_FLASH_GetError());
|
||||
}
|
||||
address += 8;
|
||||
bufp += 1;
|
||||
}
|
||||
if (HAL_FLASH_Lock() != HAL_OK) {
|
||||
return LFS_ERR_IO;
|
||||
}
|
||||
address += 8;
|
||||
bufp += 1;
|
||||
}
|
||||
if (HAL_FLASH_Lock() != HAL_OK) {
|
||||
return LFS_ERR_IO;
|
||||
}
|
||||
|
||||
return hal_rc == HAL_OK ? LFS_ERR_OK : LFS_ERR_IO; // If HAL_OK, return LFS_ERR_OK, else return LFS_ERR_IO
|
||||
return hal_rc == HAL_OK ? LFS_ERR_OK : LFS_ERR_IO; // If HAL_OK, return LFS_ERR_OK, else return LFS_ERR_IO
|
||||
}
|
||||
|
||||
// Erase a block. A block must be erased before being programmed.
|
||||
// The state of an erased block is undefined. Negative error codes
|
||||
// are propogated 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) {
|
||||
lfs_block_t address = LFS_FLASH_ADDR_BASE + (block * STM32WL_PAGE_SIZE);
|
||||
HAL_StatusTypeDef hal_rc;
|
||||
FLASH_EraseInitTypeDef EraseInitStruct = {.TypeErase = FLASH_TYPEERASE_PAGES, .Page = 0, .NbPages = 1};
|
||||
uint32_t PAGEError = 0;
|
||||
static int _internal_flash_erase(const struct lfs_config *c, lfs_block_t block)
|
||||
{
|
||||
lfs_block_t address = LFS_FLASH_ADDR_BASE + (block * STM32WL_PAGE_SIZE);
|
||||
HAL_StatusTypeDef hal_rc;
|
||||
FLASH_EraseInitTypeDef EraseInitStruct = {.TypeErase = FLASH_TYPEERASE_PAGES, .Page = 0, .NbPages = 1};
|
||||
uint32_t PAGEError = 0;
|
||||
|
||||
LFS_UNUSED(c);
|
||||
LFS_UNUSED(c);
|
||||
|
||||
if ((address < LFS_FLASH_ADDR_BASE) || (address > LFS_FLASH_ADDR_END)) {
|
||||
_LFS_DBG("Wanted to erase out of bound of FLASH: 0x%08x.\n", address);
|
||||
return LFS_ERR_INVAL;
|
||||
}
|
||||
/* calculate the absolute page, i.e. what the ST wants */
|
||||
EraseInitStruct.Page = (address - STM32WL_FLASH_BASE) / STM32WL_PAGE_SIZE;
|
||||
_LFS_DBG("Erasing block %d at 0x%08x... ", block, address);
|
||||
HAL_FLASH_Unlock();
|
||||
hal_rc = HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
|
||||
HAL_FLASH_Lock();
|
||||
if ((address < LFS_FLASH_ADDR_BASE) || (address > LFS_FLASH_ADDR_END)) {
|
||||
_LFS_DBG("Wanted to erase out of bound of FLASH: 0x%08x.\n", address);
|
||||
return LFS_ERR_INVAL;
|
||||
}
|
||||
/* calculate the absolute page, i.e. what the ST wants */
|
||||
EraseInitStruct.Page = (address - STM32WL_FLASH_BASE) / STM32WL_PAGE_SIZE;
|
||||
_LFS_DBG("Erasing block %d at 0x%08x... ", block, address);
|
||||
HAL_FLASH_Unlock();
|
||||
hal_rc = HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
|
||||
HAL_FLASH_Lock();
|
||||
|
||||
return hal_rc == HAL_OK ? LFS_ERR_OK : LFS_ERR_IO; // If HAL_OK, return LFS_ERR_OK, else return LFS_ERR_IO
|
||||
return hal_rc == HAL_OK ? LFS_ERR_OK : LFS_ERR_IO; // If HAL_OK, return LFS_ERR_OK, else return LFS_ERR_IO
|
||||
}
|
||||
|
||||
// Sync the state of the underlying block device. Negative error codes
|
||||
// are propogated to the user.
|
||||
static int _internal_flash_sync(const struct lfs_config *c) {
|
||||
LFS_UNUSED(c);
|
||||
// write function performs no caching. No need for sync.
|
||||
static int _internal_flash_sync(const struct lfs_config *c)
|
||||
{
|
||||
LFS_UNUSED(c);
|
||||
// write function performs no caching. No need for sync.
|
||||
|
||||
return LFS_ERR_OK;
|
||||
return LFS_ERR_OK;
|
||||
}
|
||||
|
||||
static struct lfs_config _InternalFSConfig = {.context = NULL,
|
||||
@@ -169,25 +173,26 @@ LittleFS InternalFS;
|
||||
|
||||
LittleFS::LittleFS(void) : STM32_LittleFS(&_InternalFSConfig) {}
|
||||
|
||||
bool LittleFS::begin(void) {
|
||||
if (FLASH_BASE >= LFS_FLASH_ADDR_BASE) {
|
||||
/* There is not enough space on this device for a filesystem. */
|
||||
return false;
|
||||
}
|
||||
// failed to mount, erase all pages then format and mount again
|
||||
if (!STM32_LittleFS::begin()) {
|
||||
// Erase all pages of internal flash region for Filesystem.
|
||||
for (uint32_t addr = LFS_FLASH_ADDR_BASE; addr < (LFS_FLASH_ADDR_END + 1); addr += STM32WL_PAGE_SIZE) {
|
||||
_internal_flash_erase(&_InternalFSConfig, (addr - LFS_FLASH_ADDR_BASE) / STM32WL_PAGE_SIZE);
|
||||
bool LittleFS::begin(void)
|
||||
{
|
||||
if (FLASH_BASE >= LFS_FLASH_ADDR_BASE) {
|
||||
/* There is not enough space on this device for a filesystem. */
|
||||
return false;
|
||||
}
|
||||
// failed to mount, erase all pages then format and mount again
|
||||
if (!STM32_LittleFS::begin()) {
|
||||
// Erase all pages of internal flash region for Filesystem.
|
||||
for (uint32_t addr = LFS_FLASH_ADDR_BASE; addr < (LFS_FLASH_ADDR_END + 1); addr += STM32WL_PAGE_SIZE) {
|
||||
_internal_flash_erase(&_InternalFSConfig, (addr - LFS_FLASH_ADDR_BASE) / STM32WL_PAGE_SIZE);
|
||||
}
|
||||
|
||||
// lfs format
|
||||
this->format();
|
||||
|
||||
// mount again if still failed, give up
|
||||
if (!STM32_LittleFS::begin())
|
||||
return false;
|
||||
}
|
||||
|
||||
// lfs format
|
||||
this->format();
|
||||
|
||||
// mount again if still failed, give up
|
||||
if (!STM32_LittleFS::begin())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -27,12 +27,13 @@
|
||||
|
||||
#include "STM32_LittleFS.h"
|
||||
|
||||
class LittleFS : public STM32_LittleFS {
|
||||
public:
|
||||
LittleFS(void);
|
||||
class LittleFS : public STM32_LittleFS
|
||||
{
|
||||
public:
|
||||
LittleFS(void);
|
||||
|
||||
// overwrite to also perform low level format (sector erase of whole flash region)
|
||||
bool begin(void);
|
||||
// overwrite to also perform low level format (sector erase of whole flash region)
|
||||
bool begin(void);
|
||||
};
|
||||
|
||||
extern LittleFS InternalFS;
|
||||
|
||||
@@ -37,10 +37,11 @@ using namespace STM32_LittleFS_Namespace;
|
||||
|
||||
STM32_LittleFS::STM32_LittleFS(void) : STM32_LittleFS(NULL) {}
|
||||
|
||||
STM32_LittleFS::STM32_LittleFS(struct lfs_config *cfg) {
|
||||
varclr(&_lfs);
|
||||
_lfs_cfg = cfg;
|
||||
_mounted = false;
|
||||
STM32_LittleFS::STM32_LittleFS(struct lfs_config *cfg)
|
||||
{
|
||||
varclr(&_lfs);
|
||||
_lfs_cfg = cfg;
|
||||
_mounted = false;
|
||||
}
|
||||
|
||||
STM32_LittleFS::~STM32_LittleFS() {}
|
||||
@@ -48,224 +49,235 @@ STM32_LittleFS::~STM32_LittleFS() {}
|
||||
// Initialize and mount the file system
|
||||
// Return true if mounted successfully else probably corrupted.
|
||||
// User should format the disk and try again
|
||||
bool STM32_LittleFS::begin(struct lfs_config *cfg) {
|
||||
_lockFS();
|
||||
bool STM32_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);
|
||||
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;
|
||||
_unlockFS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Tear down and unmount file system
|
||||
void STM32_LittleFS::end(void) {
|
||||
_lockFS();
|
||||
void STM32_LittleFS::end(void)
|
||||
{
|
||||
_lockFS();
|
||||
|
||||
if (_mounted) {
|
||||
_mounted = false;
|
||||
int err = lfs_unmount(&_lfs);
|
||||
PRINT_LFS_ERR(err);
|
||||
(void)err;
|
||||
}
|
||||
if (_mounted) {
|
||||
_mounted = false;
|
||||
int err = lfs_unmount(&_lfs);
|
||||
PRINT_LFS_ERR(err);
|
||||
(void)err;
|
||||
}
|
||||
|
||||
_unlockFS();
|
||||
_unlockFS();
|
||||
}
|
||||
|
||||
bool STM32_LittleFS::format(void) {
|
||||
_lockFS();
|
||||
bool STM32_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;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
_unlockFS();
|
||||
return LFS_ERR_OK == err;
|
||||
}
|
||||
|
||||
// Open a file or folder
|
||||
STM32_LittleFS_Namespace::File STM32_LittleFS::open(char const *filepath, uint8_t mode) {
|
||||
// No lock is required here ... the File() object will synchronize with the mutex provided
|
||||
return STM32_LittleFS_Namespace::File(filepath, mode, *this);
|
||||
STM32_LittleFS_Namespace::File STM32_LittleFS::open(char const *filepath, uint8_t mode)
|
||||
{
|
||||
// No lock is required here ... the File() object will synchronize with the mutex provided
|
||||
return STM32_LittleFS_Namespace::File(filepath, mode, *this);
|
||||
}
|
||||
|
||||
// Check if file or folder exists
|
||||
bool STM32_LittleFS::exists(char const *filepath) {
|
||||
struct lfs_info info;
|
||||
_lockFS();
|
||||
bool STM32_LittleFS::exists(char const *filepath)
|
||||
{
|
||||
struct lfs_info info;
|
||||
_lockFS();
|
||||
|
||||
bool ret = (0 == lfs_stat(&_lfs, filepath, &info));
|
||||
bool ret = (0 == lfs_stat(&_lfs, filepath, &info));
|
||||
|
||||
_unlockFS();
|
||||
return ret;
|
||||
_unlockFS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Create a directory, create intermediate parent if needed
|
||||
bool STM32_LittleFS::mkdir(char const *filepath) {
|
||||
bool ret = true;
|
||||
const char *slash = filepath;
|
||||
if (slash[0] == '/')
|
||||
slash++; // skip root '/'
|
||||
bool STM32_LittleFS::mkdir(char const *filepath)
|
||||
{
|
||||
bool ret = true;
|
||||
const char *slash = filepath;
|
||||
if (slash[0] == '/')
|
||||
slash++; // skip root '/'
|
||||
|
||||
_lockFS();
|
||||
_lockFS();
|
||||
|
||||
// make intermediate parent directory(ies)
|
||||
while (NULL != (slash = strchr(slash, '/'))) {
|
||||
char parent[slash - filepath + 1] = {0};
|
||||
memcpy(parent, filepath, slash - filepath);
|
||||
// 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;
|
||||
int rc = lfs_mkdir(&_lfs, parent);
|
||||
if (rc != LFS_ERR_OK && rc != LFS_ERR_EXIST) {
|
||||
PRINT_LFS_ERR(rc);
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
slash++;
|
||||
}
|
||||
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;
|
||||
// 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;
|
||||
_unlockFS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Remove a file
|
||||
bool STM32_LittleFS::remove(char const *filepath) {
|
||||
_lockFS();
|
||||
bool STM32_LittleFS::remove(char const *filepath)
|
||||
{
|
||||
_lockFS();
|
||||
|
||||
int err = lfs_remove(&_lfs, filepath);
|
||||
PRINT_LFS_ERR(err);
|
||||
int err = lfs_remove(&_lfs, filepath);
|
||||
PRINT_LFS_ERR(err);
|
||||
|
||||
_unlockFS();
|
||||
return LFS_ERR_OK == err;
|
||||
_unlockFS();
|
||||
return LFS_ERR_OK == err;
|
||||
}
|
||||
|
||||
// Rename a file
|
||||
bool STM32_LittleFS::rename(char const *oldfilepath, char const *newfilepath) {
|
||||
_lockFS();
|
||||
bool STM32_LittleFS::rename(char const *oldfilepath, char const *newfilepath)
|
||||
{
|
||||
_lockFS();
|
||||
|
||||
int err = lfs_rename(&_lfs, oldfilepath, newfilepath);
|
||||
PRINT_LFS_ERR(err);
|
||||
int err = lfs_rename(&_lfs, oldfilepath, newfilepath);
|
||||
PRINT_LFS_ERR(err);
|
||||
|
||||
_unlockFS();
|
||||
return LFS_ERR_OK == err;
|
||||
_unlockFS();
|
||||
return LFS_ERR_OK == err;
|
||||
}
|
||||
|
||||
// Remove a folder
|
||||
bool STM32_LittleFS::rmdir(char const *filepath) {
|
||||
_lockFS();
|
||||
bool STM32_LittleFS::rmdir(char const *filepath)
|
||||
{
|
||||
_lockFS();
|
||||
|
||||
int err = lfs_remove(&_lfs, filepath);
|
||||
PRINT_LFS_ERR(err);
|
||||
int err = lfs_remove(&_lfs, filepath);
|
||||
PRINT_LFS_ERR(err);
|
||||
|
||||
_unlockFS();
|
||||
return LFS_ERR_OK == err;
|
||||
_unlockFS();
|
||||
return LFS_ERR_OK == err;
|
||||
}
|
||||
|
||||
// Remove a folder recursively
|
||||
bool STM32_LittleFS::rmdir_r(char const *filepath) {
|
||||
/* 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();
|
||||
bool STM32_LittleFS::rmdir_r(char const *filepath)
|
||||
{
|
||||
/* 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);
|
||||
int err = lfs_remove(&_lfs, filepath);
|
||||
PRINT_LFS_ERR(err);
|
||||
|
||||
_unlockFS();
|
||||
return LFS_ERR_OK == 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";
|
||||
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;
|
||||
}
|
||||
default:
|
||||
static char errcode[10];
|
||||
sprintf(errcode, "%ld", err);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,57 +33,60 @@
|
||||
#include "STM32_LittleFS_File.h"
|
||||
#include "littlefs/lfs.h"
|
||||
|
||||
class STM32_LittleFS {
|
||||
public:
|
||||
STM32_LittleFS(void);
|
||||
explicit STM32_LittleFS(struct lfs_config *cfg);
|
||||
virtual ~STM32_LittleFS();
|
||||
class STM32_LittleFS
|
||||
{
|
||||
public:
|
||||
STM32_LittleFS(void);
|
||||
explicit STM32_LittleFS(struct lfs_config *cfg);
|
||||
virtual ~STM32_LittleFS();
|
||||
|
||||
bool begin(struct lfs_config *cfg = NULL);
|
||||
void end(void);
|
||||
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.
|
||||
STM32_LittleFS_Namespace::File open(char const *filename, uint8_t mode = STM32_LittleFS_Namespace::FILE_O_READ);
|
||||
// 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.
|
||||
STM32_LittleFS_Namespace::File open(char const *filename, uint8_t mode = STM32_LittleFS_Namespace::FILE_O_READ);
|
||||
|
||||
// Methods to determine if the requested file path exists.
|
||||
bool exists(char const *filepath);
|
||||
// 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);
|
||||
// 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);
|
||||
// Delete the file.
|
||||
bool remove(char const *filepath);
|
||||
|
||||
// Rename the file.
|
||||
bool rename(char const *oldfilepath, char const *newfilepath);
|
||||
// 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 (must be empty)
|
||||
bool rmdir(char const *filepath);
|
||||
|
||||
// Delete a folder (recursively)
|
||||
bool rmdir_r(char const *filepath);
|
||||
// Delete a folder (recursively)
|
||||
bool rmdir_r(char const *filepath);
|
||||
|
||||
// format file system
|
||||
bool format(void);
|
||||
// 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) { /* no-op */
|
||||
}
|
||||
void _unlockFS(void) { /* no-op */
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
/* 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)
|
||||
{ /* no-op */
|
||||
}
|
||||
void _unlockFS(void)
|
||||
{ /* no-op */
|
||||
}
|
||||
|
||||
protected:
|
||||
bool _mounted;
|
||||
struct lfs_config *_lfs_cfg;
|
||||
lfs_t _lfs;
|
||||
protected:
|
||||
bool _mounted;
|
||||
struct lfs_config *_lfs_cfg;
|
||||
lfs_t _lfs;
|
||||
};
|
||||
|
||||
#if !CFG_DEBUG
|
||||
@@ -91,12 +94,12 @@ protected:
|
||||
#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) { \
|
||||
printf("%s:%d, LFS error: %d\n", __FILE__, __LINE__, _err); \
|
||||
} \
|
||||
} while (0) // LFS_ERR are of type int, VERIFY_MESS expects long_int
|
||||
#define PRINT_LFS_ERR(_err) \
|
||||
do { \
|
||||
if (_err) { \
|
||||
printf("%s:%d, LFS error: %d\n", __FILE__, __LINE__, _err); \
|
||||
} \
|
||||
} while (0) // LFS_ERR are of type int, VERIFY_MESS expects long_int
|
||||
|
||||
const char *dbg_strerr_lfs(int32_t err);
|
||||
#endif
|
||||
|
||||
@@ -34,324 +34,360 @@
|
||||
|
||||
using namespace STM32_LittleFS_Namespace;
|
||||
|
||||
File::File(STM32_LittleFS &fs) {
|
||||
_fs = &fs;
|
||||
_is_dir = false;
|
||||
_name[0] = 0;
|
||||
_name[LFS_NAME_MAX] = 0;
|
||||
_dir_path = NULL;
|
||||
File::File(STM32_LittleFS &fs)
|
||||
{
|
||||
_fs = &fs;
|
||||
_is_dir = false;
|
||||
_name[0] = 0;
|
||||
_name[LFS_NAME_MAX] = 0;
|
||||
_dir_path = NULL;
|
||||
|
||||
_dir = NULL;
|
||||
_file = NULL;
|
||||
_dir = NULL;
|
||||
_file = NULL;
|
||||
}
|
||||
|
||||
File::File(char const *filename, uint8_t mode, STM32_LittleFS &fs) : File(fs) {
|
||||
// public constructor calls public API open(), which will obtain the mutex
|
||||
this->open(filename, mode);
|
||||
File::File(char const *filename, uint8_t mode, STM32_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;
|
||||
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 *)rtos_malloc(sizeof(lfs_file_t));
|
||||
if (!_file)
|
||||
return false;
|
||||
if (flags) {
|
||||
_file = (lfs_file_t *)rtos_malloc(sizeof(lfs_file_t));
|
||||
if (!_file)
|
||||
return false;
|
||||
|
||||
int rc = lfs_file_open(_fs->_getFS(), _file, filepath, flags);
|
||||
int rc = lfs_file_open(_fs->_getFS(), _file, filepath, flags);
|
||||
|
||||
if (rc) {
|
||||
// failed to open
|
||||
PRINT_LFS_ERR(rc);
|
||||
// free memory
|
||||
rtos_free(_file);
|
||||
_file = NULL;
|
||||
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 *)rtos_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);
|
||||
// free memory
|
||||
rtos_free(_file);
|
||||
_file = NULL;
|
||||
return false;
|
||||
// failed to open
|
||||
PRINT_LFS_ERR(rc);
|
||||
// free memory
|
||||
rtos_free(_dir);
|
||||
_dir = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// move to end of file
|
||||
if (mode == FILE_O_WRITE)
|
||||
lfs_file_seek(_fs->_getFS(), _file, 0, LFS_SEEK_END);
|
||||
_is_dir = true;
|
||||
|
||||
_is_dir = false;
|
||||
}
|
||||
_dir_path = (char *)rtos_malloc(strlen(filepath) + 1);
|
||||
strcpy(_dir_path, filepath);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool File::_open_dir(char const *filepath) {
|
||||
_dir = (lfs_dir_t *)rtos_malloc(sizeof(lfs_dir_t));
|
||||
if (!_dir)
|
||||
return false;
|
||||
bool File::open(char const *filepath, uint8_t mode)
|
||||
{
|
||||
bool ret = false;
|
||||
_fs->_lockFS();
|
||||
|
||||
int rc = lfs_dir_open(_fs->_getFS(), _dir, filepath);
|
||||
ret = this->_open(filepath, mode);
|
||||
|
||||
if (rc) {
|
||||
// failed to open
|
||||
PRINT_LFS_ERR(rc);
|
||||
// free memory
|
||||
rtos_free(_dir);
|
||||
_dir = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
_is_dir = true;
|
||||
|
||||
_dir_path = (char *)rtos_malloc(strlen(filepath) + 1);
|
||||
strcpy(_dir_path, filepath);
|
||||
|
||||
return true;
|
||||
_fs->_unlockFS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool File::open(char const *filepath, uint8_t mode) {
|
||||
bool ret = false;
|
||||
_fs->_lockFS();
|
||||
bool File::_open(char const *filepath, uint8_t mode)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
ret = this->_open(filepath, mode);
|
||||
// close if currently opened
|
||||
if (this->isOpen())
|
||||
_close();
|
||||
|
||||
_fs->_unlockFS();
|
||||
return ret;
|
||||
}
|
||||
struct lfs_info info;
|
||||
int rc = lfs_stat(_fs->_getFS(), filepath, &info);
|
||||
|
||||
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<int>(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<int>(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 file_size = lfs_file_size(_fs->_getFS(), _file);
|
||||
uint32_t pos = lfs_file_tell(_fs->_getFS(), _file);
|
||||
ret = file_size - 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);
|
||||
rtos_free(_dir);
|
||||
_dir = NULL;
|
||||
|
||||
if (this->_dir_path)
|
||||
rtos_free(_dir_path);
|
||||
_dir_path = NULL;
|
||||
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 {
|
||||
lfs_file_close(this->_fs->_getFS(), _file);
|
||||
rtos_free(_file);
|
||||
_file = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
File::operator bool(void) { return isOpen(); }
|
||||
size_t File::write(uint8_t ch)
|
||||
{
|
||||
return write(&ch, 1);
|
||||
}
|
||||
|
||||
bool File::isOpen(void) { return (_file != NULL) || (_dir != NULL); }
|
||||
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<int>(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<int>(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 file_size = lfs_file_size(_fs->_getFS(), _file);
|
||||
uint32_t pos = lfs_file_tell(_fs->_getFS(), _file);
|
||||
ret = file_size - 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);
|
||||
rtos_free(_dir);
|
||||
_dir = NULL;
|
||||
|
||||
if (this->_dir_path)
|
||||
rtos_free(_dir_path);
|
||||
_dir_path = NULL;
|
||||
} else {
|
||||
lfs_file_close(this->_fs->_getFS(), _file);
|
||||
rtos_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; }
|
||||
char const *File::name(void)
|
||||
{
|
||||
return this->_name;
|
||||
}
|
||||
|
||||
bool File::isDirectory(void) { return this->_is_dir; }
|
||||
bool File::isDirectory(void)
|
||||
{
|
||||
return this->_is_dir;
|
||||
}
|
||||
|
||||
File File::openNextFile(uint8_t mode) {
|
||||
_fs->_lockFS();
|
||||
File File::openNextFile(uint8_t mode)
|
||||
{
|
||||
_fs->_lockFS();
|
||||
|
||||
File ret(*_fs);
|
||||
if (this->_is_dir) {
|
||||
struct lfs_info info;
|
||||
int rc;
|
||||
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)));
|
||||
// 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);
|
||||
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);
|
||||
(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;
|
||||
_fs->_unlockFS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void File::rewindDirectory(void) {
|
||||
_fs->_lockFS();
|
||||
if (this->_is_dir) {
|
||||
lfs_dir_rewind(_fs->_getFS(), _dir);
|
||||
}
|
||||
_fs->_unlockFS();
|
||||
void File::rewindDirectory(void)
|
||||
{
|
||||
_fs->_lockFS();
|
||||
if (this->_is_dir) {
|
||||
lfs_dir_rewind(_fs->_getFS(), _dir);
|
||||
}
|
||||
_fs->_unlockFS();
|
||||
}
|
||||
|
||||
@@ -30,74 +30,77 @@
|
||||
// Forward declaration
|
||||
class STM32_LittleFS;
|
||||
|
||||
namespace STM32_LittleFS_Namespace {
|
||||
namespace STM32_LittleFS_Namespace
|
||||
{
|
||||
|
||||
// avoid conflict with other FileSystem FILE_READ/FILE_WRITE
|
||||
enum {
|
||||
FILE_O_READ = 0,
|
||||
FILE_O_WRITE = 1,
|
||||
FILE_O_READ = 0,
|
||||
FILE_O_WRITE = 1,
|
||||
};
|
||||
|
||||
class File : public Stream {
|
||||
public:
|
||||
explicit File(STM32_LittleFS &fs);
|
||||
File(char const *filename, uint8_t mode, STM32_LittleFS &fs);
|
||||
class File : public Stream
|
||||
{
|
||||
public:
|
||||
explicit File(STM32_LittleFS &fs);
|
||||
File(char const *filename, uint8_t mode, STM32_LittleFS &fs);
|
||||
|
||||
public:
|
||||
bool open(char const *filename, uint8_t mode);
|
||||
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); }
|
||||
//------------- 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 read(void);
|
||||
int read(void *buf, uint16_t nbyte);
|
||||
|
||||
virtual int peek(void);
|
||||
virtual int available(void);
|
||||
virtual void flush(void);
|
||||
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 seek(uint32_t pos);
|
||||
uint32_t position(void);
|
||||
uint32_t size(void);
|
||||
|
||||
bool truncate(uint32_t pos);
|
||||
bool truncate(void);
|
||||
bool truncate(uint32_t pos);
|
||||
bool truncate(void);
|
||||
|
||||
void close(void);
|
||||
void close(void);
|
||||
|
||||
operator bool(void);
|
||||
operator bool(void);
|
||||
|
||||
bool isOpen(void);
|
||||
char const *name(void);
|
||||
bool isOpen(void);
|
||||
char const *name(void);
|
||||
|
||||
bool isDirectory(void);
|
||||
File openNextFile(uint8_t mode = FILE_O_READ);
|
||||
void rewindDirectory(void);
|
||||
bool isDirectory(void);
|
||||
File openNextFile(uint8_t mode = FILE_O_READ);
|
||||
void rewindDirectory(void);
|
||||
|
||||
private:
|
||||
STM32_LittleFS *_fs;
|
||||
private:
|
||||
STM32_LittleFS *_fs;
|
||||
|
||||
bool _is_dir;
|
||||
bool _is_dir;
|
||||
|
||||
union {
|
||||
lfs_file_t *_file;
|
||||
lfs_dir_t *_dir;
|
||||
};
|
||||
union {
|
||||
lfs_file_t *_file;
|
||||
lfs_dir_t *_dir;
|
||||
};
|
||||
|
||||
char *_dir_path;
|
||||
char _name[LFS_NAME_MAX + 1];
|
||||
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);
|
||||
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 STM32_LittleFS_Namespace
|
||||
|
||||
@@ -34,6 +34,6 @@
|
||||
#define SX126X_BUSY 1004
|
||||
|
||||
#if !defined(DEBUG_MUTE) && !defined(PIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF)
|
||||
#error \
|
||||
#error \
|
||||
"You MUST enable PIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF if debug prints are enabled. printf will print uninitialized garbage instead of floats."
|
||||
#endif
|
||||
+2386
-2298
File diff suppressed because it is too large
Load Diff
+152
-152
@@ -49,230 +49,230 @@ typedef uint32_t lfs_block_t;
|
||||
// Possible error codes, these are negative to allow
|
||||
// valid positive return values
|
||||
enum lfs_error {
|
||||
LFS_ERR_OK = 0, // No error
|
||||
LFS_ERR_IO = -5, // Error during device operation
|
||||
LFS_ERR_CORRUPT = -52, // Corrupted
|
||||
LFS_ERR_NOENT = -2, // No directory entry
|
||||
LFS_ERR_EXIST = -17, // Entry already exists
|
||||
LFS_ERR_NOTDIR = -20, // Entry is not a dir
|
||||
LFS_ERR_ISDIR = -21, // Entry is a dir
|
||||
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
|
||||
LFS_ERR_BADF = -9, // Bad file number
|
||||
LFS_ERR_INVAL = -22, // Invalid parameter
|
||||
LFS_ERR_NOSPC = -28, // No space left on device
|
||||
LFS_ERR_NOMEM = -12, // No more memory available
|
||||
LFS_ERR_OK = 0, // No error
|
||||
LFS_ERR_IO = -5, // Error during device operation
|
||||
LFS_ERR_CORRUPT = -52, // Corrupted
|
||||
LFS_ERR_NOENT = -2, // No directory entry
|
||||
LFS_ERR_EXIST = -17, // Entry already exists
|
||||
LFS_ERR_NOTDIR = -20, // Entry is not a dir
|
||||
LFS_ERR_ISDIR = -21, // Entry is a dir
|
||||
LFS_ERR_NOTEMPTY = -39, // Dir is not empty
|
||||
LFS_ERR_BADF = -9, // Bad file number
|
||||
LFS_ERR_INVAL = -22, // Invalid parameter
|
||||
LFS_ERR_NOSPC = -28, // No space left on device
|
||||
LFS_ERR_NOMEM = -12, // No more memory available
|
||||
};
|
||||
|
||||
// File types
|
||||
enum lfs_type {
|
||||
LFS_TYPE_REG = 0x11,
|
||||
LFS_TYPE_DIR = 0x22,
|
||||
LFS_TYPE_SUPERBLOCK = 0x2e,
|
||||
LFS_TYPE_REG = 0x11,
|
||||
LFS_TYPE_DIR = 0x22,
|
||||
LFS_TYPE_SUPERBLOCK = 0x2e,
|
||||
};
|
||||
|
||||
// File open flags
|
||||
enum lfs_open_flags {
|
||||
// open flags
|
||||
LFS_O_RDONLY = 1, // Open a file as read only
|
||||
LFS_O_WRONLY = 2, // Open a file as write only
|
||||
LFS_O_RDWR = 3, // Open a file as read and write
|
||||
LFS_O_CREAT = 0x0100, // Create a file if it does not exist
|
||||
LFS_O_EXCL = 0x0200, // Fail if a file already exists
|
||||
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
|
||||
LFS_O_APPEND = 0x0800, // Move to end of file on every write
|
||||
// open flags
|
||||
LFS_O_RDONLY = 1, // Open a file as read only
|
||||
LFS_O_WRONLY = 2, // Open a file as write only
|
||||
LFS_O_RDWR = 3, // Open a file as read and write
|
||||
LFS_O_CREAT = 0x0100, // Create a file if it does not exist
|
||||
LFS_O_EXCL = 0x0200, // Fail if a file already exists
|
||||
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
|
||||
LFS_O_APPEND = 0x0800, // Move to end of file on every write
|
||||
|
||||
// internally used flags
|
||||
LFS_F_DIRTY = 0x10000, // File does not match storage
|
||||
LFS_F_WRITING = 0x20000, // File has been written since last flush
|
||||
LFS_F_READING = 0x40000, // File has been read since last flush
|
||||
LFS_F_ERRED = 0x80000, // An error occured during write
|
||||
// internally used flags
|
||||
LFS_F_DIRTY = 0x10000, // File does not match storage
|
||||
LFS_F_WRITING = 0x20000, // File has been written since last flush
|
||||
LFS_F_READING = 0x40000, // File has been read since last flush
|
||||
LFS_F_ERRED = 0x80000, // An error occured during write
|
||||
};
|
||||
|
||||
// File seek flags
|
||||
enum lfs_whence_flags {
|
||||
LFS_SEEK_SET = 0, // Seek relative to an absolute position
|
||||
LFS_SEEK_CUR = 1, // Seek relative to the current file position
|
||||
LFS_SEEK_END = 2, // Seek relative to the end of the file
|
||||
LFS_SEEK_SET = 0, // Seek relative to an absolute position
|
||||
LFS_SEEK_CUR = 1, // Seek relative to the current file position
|
||||
LFS_SEEK_END = 2, // Seek relative to the end of the file
|
||||
};
|
||||
|
||||
// Configuration provided during initialization of the littlefs
|
||||
struct lfs_config {
|
||||
// Opaque user provided context that can be used to pass
|
||||
// information to the block device operations
|
||||
void *context;
|
||||
// Opaque user provided context that can be used to pass
|
||||
// information to the block device operations
|
||||
void *context;
|
||||
|
||||
// Read a region in a block. Negative error codes are propogated
|
||||
// to the user.
|
||||
int (*read)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size);
|
||||
// Read a region in a block. Negative error codes are propogated
|
||||
// to the user.
|
||||
int (*read)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size);
|
||||
|
||||
// Program a region in a block. The block must have previously
|
||||
// been erased. Negative error codes are propogated to the user.
|
||||
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
int (*prog)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size);
|
||||
// Program a region in a block. The block must have previously
|
||||
// been erased. Negative error codes are propogated to the user.
|
||||
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
int (*prog)(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size);
|
||||
|
||||
// Erase a block. A block must be erased before being programmed.
|
||||
// The state of an erased block is undefined. Negative error codes
|
||||
// are propogated to the user.
|
||||
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
int (*erase)(const struct lfs_config *c, lfs_block_t block);
|
||||
// Erase a block. A block must be erased before being programmed.
|
||||
// The state of an erased block is undefined. Negative error codes
|
||||
// are propogated to the user.
|
||||
// May return LFS_ERR_CORRUPT if the block should be considered bad.
|
||||
int (*erase)(const struct lfs_config *c, lfs_block_t block);
|
||||
|
||||
// Sync the state of the underlying block device. Negative error codes
|
||||
// are propogated to the user.
|
||||
int (*sync)(const struct lfs_config *c);
|
||||
// Sync the state of the underlying block device. Negative error codes
|
||||
// are propogated to the user.
|
||||
int (*sync)(const struct lfs_config *c);
|
||||
|
||||
// Minimum size of a block read. This determines the size of read buffers.
|
||||
// This may be larger than the physical read size to improve performance
|
||||
// by caching more of the block device.
|
||||
lfs_size_t read_size;
|
||||
// Minimum size of a block read. This determines the size of read buffers.
|
||||
// This may be larger than the physical read size to improve performance
|
||||
// by caching more of the block device.
|
||||
lfs_size_t read_size;
|
||||
|
||||
// Minimum size of a block program. This determines the size of program
|
||||
// buffers. This may be larger than the physical program size to improve
|
||||
// performance by caching more of the block device.
|
||||
// Must be a multiple of the read size.
|
||||
lfs_size_t prog_size;
|
||||
// Minimum size of a block program. This determines the size of program
|
||||
// buffers. This may be larger than the physical program size to improve
|
||||
// performance by caching more of the block device.
|
||||
// Must be a multiple of the read size.
|
||||
lfs_size_t prog_size;
|
||||
|
||||
// Size of an erasable block. This does not impact ram consumption and
|
||||
// may be larger than the physical erase size. However, this should be
|
||||
// kept small as each file currently takes up an entire block.
|
||||
// Must be a multiple of the program size.
|
||||
lfs_size_t block_size;
|
||||
// Size of an erasable block. This does not impact ram consumption and
|
||||
// may be larger than the physical erase size. However, this should be
|
||||
// kept small as each file currently takes up an entire block.
|
||||
// Must be a multiple of the program size.
|
||||
lfs_size_t block_size;
|
||||
|
||||
// Number of erasable blocks on the device.
|
||||
lfs_size_t block_count;
|
||||
// Number of erasable blocks on the device.
|
||||
lfs_size_t block_count;
|
||||
|
||||
// Number of blocks to lookahead during block allocation. A larger
|
||||
// lookahead reduces the number of passes required to allocate a block.
|
||||
// The lookahead buffer requires only 1 bit per block so it can be quite
|
||||
// large with little ram impact. Should be a multiple of 32.
|
||||
lfs_size_t lookahead;
|
||||
// Number of blocks to lookahead during block allocation. A larger
|
||||
// lookahead reduces the number of passes required to allocate a block.
|
||||
// The lookahead buffer requires only 1 bit per block so it can be quite
|
||||
// large with little ram impact. Should be a multiple of 32.
|
||||
lfs_size_t lookahead;
|
||||
|
||||
// Optional, statically allocated read buffer. Must be read sized.
|
||||
void *read_buffer;
|
||||
// Optional, statically allocated read buffer. Must be read sized.
|
||||
void *read_buffer;
|
||||
|
||||
// Optional, statically allocated program buffer. Must be program sized.
|
||||
void *prog_buffer;
|
||||
// Optional, statically allocated program buffer. Must be program sized.
|
||||
void *prog_buffer;
|
||||
|
||||
// Optional, statically allocated lookahead buffer. Must be 1 bit per
|
||||
// lookahead block.
|
||||
void *lookahead_buffer;
|
||||
// Optional, statically allocated lookahead buffer. Must be 1 bit per
|
||||
// lookahead block.
|
||||
void *lookahead_buffer;
|
||||
|
||||
// Optional, statically allocated buffer for files. Must be program sized.
|
||||
// If enabled, only one file may be opened at a time.
|
||||
void *file_buffer;
|
||||
// Optional, statically allocated buffer for files. Must be program sized.
|
||||
// If enabled, only one file may be opened at a time.
|
||||
void *file_buffer;
|
||||
};
|
||||
|
||||
// Optional configuration provided during lfs_file_opencfg
|
||||
struct lfs_file_config {
|
||||
// Optional, statically allocated buffer for files. Must be program sized.
|
||||
// If NULL, malloc will be used by default.
|
||||
void *buffer;
|
||||
// Optional, statically allocated buffer for files. Must be program sized.
|
||||
// If NULL, malloc will be used by default.
|
||||
void *buffer;
|
||||
};
|
||||
|
||||
// File info structure
|
||||
struct lfs_info {
|
||||
// Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
|
||||
uint8_t type;
|
||||
// Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR
|
||||
uint8_t type;
|
||||
|
||||
// Size of the file, only valid for REG files
|
||||
lfs_size_t size;
|
||||
// Size of the file, only valid for REG files
|
||||
lfs_size_t size;
|
||||
|
||||
// Name of the file stored as a null-terminated string
|
||||
char name[LFS_NAME_MAX + 1];
|
||||
// Name of the file stored as a null-terminated string
|
||||
char name[LFS_NAME_MAX + 1];
|
||||
};
|
||||
|
||||
/// littlefs data structures ///
|
||||
typedef struct lfs_entry {
|
||||
lfs_off_t off;
|
||||
lfs_off_t off;
|
||||
|
||||
struct lfs_disk_entry {
|
||||
uint8_t type;
|
||||
uint8_t elen;
|
||||
uint8_t alen;
|
||||
uint8_t nlen;
|
||||
union {
|
||||
struct {
|
||||
lfs_block_t head;
|
||||
lfs_size_t size;
|
||||
} file;
|
||||
lfs_block_t dir[2];
|
||||
} u;
|
||||
} d;
|
||||
struct lfs_disk_entry {
|
||||
uint8_t type;
|
||||
uint8_t elen;
|
||||
uint8_t alen;
|
||||
uint8_t nlen;
|
||||
union {
|
||||
struct {
|
||||
lfs_block_t head;
|
||||
lfs_size_t size;
|
||||
} file;
|
||||
lfs_block_t dir[2];
|
||||
} u;
|
||||
} d;
|
||||
} lfs_entry_t;
|
||||
|
||||
typedef struct lfs_cache {
|
||||
lfs_block_t block;
|
||||
lfs_off_t off;
|
||||
uint8_t *buffer;
|
||||
lfs_block_t block;
|
||||
lfs_off_t off;
|
||||
uint8_t *buffer;
|
||||
} lfs_cache_t;
|
||||
|
||||
typedef struct lfs_file {
|
||||
struct lfs_file *next;
|
||||
lfs_block_t pair[2];
|
||||
lfs_off_t poff;
|
||||
struct lfs_file *next;
|
||||
lfs_block_t pair[2];
|
||||
lfs_off_t poff;
|
||||
|
||||
lfs_block_t head;
|
||||
lfs_size_t size;
|
||||
lfs_block_t head;
|
||||
lfs_size_t size;
|
||||
|
||||
const struct lfs_file_config *cfg;
|
||||
uint32_t flags;
|
||||
lfs_off_t pos;
|
||||
lfs_block_t block;
|
||||
lfs_off_t off;
|
||||
lfs_cache_t cache;
|
||||
const struct lfs_file_config *cfg;
|
||||
uint32_t flags;
|
||||
lfs_off_t pos;
|
||||
lfs_block_t block;
|
||||
lfs_off_t off;
|
||||
lfs_cache_t cache;
|
||||
} lfs_file_t;
|
||||
|
||||
typedef struct lfs_dir {
|
||||
struct lfs_dir *next;
|
||||
lfs_block_t pair[2];
|
||||
lfs_off_t off;
|
||||
struct lfs_dir *next;
|
||||
lfs_block_t pair[2];
|
||||
lfs_off_t off;
|
||||
|
||||
lfs_block_t head[2];
|
||||
lfs_off_t pos;
|
||||
lfs_block_t head[2];
|
||||
lfs_off_t pos;
|
||||
|
||||
struct lfs_disk_dir {
|
||||
uint32_t rev;
|
||||
lfs_size_t size;
|
||||
lfs_block_t tail[2];
|
||||
} d;
|
||||
struct lfs_disk_dir {
|
||||
uint32_t rev;
|
||||
lfs_size_t size;
|
||||
lfs_block_t tail[2];
|
||||
} d;
|
||||
} lfs_dir_t;
|
||||
|
||||
typedef struct lfs_superblock {
|
||||
lfs_off_t off;
|
||||
lfs_off_t off;
|
||||
|
||||
struct lfs_disk_superblock {
|
||||
uint8_t type;
|
||||
uint8_t elen;
|
||||
uint8_t alen;
|
||||
uint8_t nlen;
|
||||
lfs_block_t root[2];
|
||||
uint32_t block_size;
|
||||
uint32_t block_count;
|
||||
uint32_t version;
|
||||
char magic[8];
|
||||
} d;
|
||||
struct lfs_disk_superblock {
|
||||
uint8_t type;
|
||||
uint8_t elen;
|
||||
uint8_t alen;
|
||||
uint8_t nlen;
|
||||
lfs_block_t root[2];
|
||||
uint32_t block_size;
|
||||
uint32_t block_count;
|
||||
uint32_t version;
|
||||
char magic[8];
|
||||
} d;
|
||||
} lfs_superblock_t;
|
||||
|
||||
typedef struct lfs_free {
|
||||
lfs_block_t off;
|
||||
lfs_block_t size;
|
||||
lfs_block_t i;
|
||||
lfs_block_t ack;
|
||||
uint32_t *buffer;
|
||||
lfs_block_t off;
|
||||
lfs_block_t size;
|
||||
lfs_block_t i;
|
||||
lfs_block_t ack;
|
||||
uint32_t *buffer;
|
||||
} lfs_free_t;
|
||||
|
||||
// The littlefs type
|
||||
typedef struct lfs {
|
||||
const struct lfs_config *cfg;
|
||||
const struct lfs_config *cfg;
|
||||
|
||||
lfs_block_t root[2];
|
||||
lfs_file_t *files;
|
||||
lfs_dir_t *dirs;
|
||||
lfs_block_t root[2];
|
||||
lfs_file_t *files;
|
||||
lfs_dir_t *dirs;
|
||||
|
||||
lfs_cache_t rcache;
|
||||
lfs_cache_t pcache;
|
||||
lfs_cache_t rcache;
|
||||
lfs_cache_t pcache;
|
||||
|
||||
lfs_free_t free;
|
||||
bool deorphaned;
|
||||
lfs_free_t free;
|
||||
bool deorphaned;
|
||||
} lfs_t;
|
||||
|
||||
/// Filesystem functions ///
|
||||
|
||||
@@ -10,18 +10,19 @@
|
||||
#ifndef LFS_CONFIG
|
||||
|
||||
// Software CRC implementation with small lookup table
|
||||
void lfs_crc(uint32_t *restrict crc, const void *buffer, size_t size) {
|
||||
static const uint32_t rtable[16] = {
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
||||
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
|
||||
};
|
||||
void lfs_crc(uint32_t *restrict crc, const void *buffer, size_t size)
|
||||
{
|
||||
static const uint32_t rtable[16] = {
|
||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
||||
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
|
||||
};
|
||||
|
||||
const uint8_t *data = buffer;
|
||||
const uint8_t *data = buffer;
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
*crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 0)) & 0xf];
|
||||
*crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 4)) & 0xf];
|
||||
}
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
*crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 0)) & 0xf];
|
||||
*crc = (*crc >> 4) ^ rtable[(*crc ^ (data[i] >> 4)) & 0xf];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -80,96 +80,114 @@ extern "C" {
|
||||
// expensive basic C implementation for debugging purposes
|
||||
|
||||
// Min/max functions for unsigned 32-bit numbers
|
||||
static inline uint32_t lfs_max(uint32_t a, uint32_t b) { return (a > b) ? a : b; }
|
||||
static inline uint32_t lfs_max(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
static inline uint32_t lfs_min(uint32_t a, uint32_t b) { return (a < b) ? a : b; }
|
||||
static inline uint32_t lfs_min(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
// Find the next smallest power of 2 less than or equal to a
|
||||
static inline uint32_t lfs_npw2(uint32_t a) {
|
||||
static inline uint32_t lfs_npw2(uint32_t a)
|
||||
{
|
||||
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
|
||||
return 32 - __builtin_clz(a - 1);
|
||||
return 32 - __builtin_clz(a - 1);
|
||||
#else
|
||||
uint32_t r = 0;
|
||||
uint32_t s;
|
||||
a -= 1;
|
||||
s = (a > 0xffff) << 4;
|
||||
a >>= s;
|
||||
r |= s;
|
||||
s = (a > 0xff) << 3;
|
||||
a >>= s;
|
||||
r |= s;
|
||||
s = (a > 0xf) << 2;
|
||||
a >>= s;
|
||||
r |= s;
|
||||
s = (a > 0x3) << 1;
|
||||
a >>= s;
|
||||
r |= s;
|
||||
return (r | (a >> 1)) + 1;
|
||||
uint32_t r = 0;
|
||||
uint32_t s;
|
||||
a -= 1;
|
||||
s = (a > 0xffff) << 4;
|
||||
a >>= s;
|
||||
r |= s;
|
||||
s = (a > 0xff) << 3;
|
||||
a >>= s;
|
||||
r |= s;
|
||||
s = (a > 0xf) << 2;
|
||||
a >>= s;
|
||||
r |= s;
|
||||
s = (a > 0x3) << 1;
|
||||
a >>= s;
|
||||
r |= s;
|
||||
return (r | (a >> 1)) + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Count the number of trailing binary zeros in a
|
||||
// lfs_ctz(0) may be undefined
|
||||
static inline uint32_t lfs_ctz(uint32_t a) {
|
||||
static inline uint32_t lfs_ctz(uint32_t a)
|
||||
{
|
||||
#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__)
|
||||
return __builtin_ctz(a);
|
||||
return __builtin_ctz(a);
|
||||
#else
|
||||
return lfs_npw2((a & -a) + 1) - 1;
|
||||
return lfs_npw2((a & -a) + 1) - 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Count the number of binary ones in a
|
||||
static inline uint32_t lfs_popc(uint32_t a) {
|
||||
static inline uint32_t lfs_popc(uint32_t a)
|
||||
{
|
||||
#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
|
||||
return __builtin_popcount(a);
|
||||
return __builtin_popcount(a);
|
||||
#else
|
||||
a = a - ((a >> 1) & 0x55555555);
|
||||
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
|
||||
return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
|
||||
a = a - ((a >> 1) & 0x55555555);
|
||||
a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
|
||||
return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Find the sequence comparison of a and b, this is the distance
|
||||
// between a and b ignoring overflow
|
||||
static inline int lfs_scmp(uint32_t a, uint32_t b) { return (int)(unsigned)(a - b); }
|
||||
static inline int lfs_scmp(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (int)(unsigned)(a - b);
|
||||
}
|
||||
|
||||
// Convert from 32-bit little-endian to native order
|
||||
static inline uint32_t lfs_fromle32(uint32_t a) {
|
||||
#if !defined(LFS_NO_INTRINSICS) && \
|
||||
((defined(BYTE_ORDER) && BYTE_ORDER == ORDER_LITTLE_ENDIAN) || (defined(__BYTE_ORDER) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \
|
||||
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||
return a;
|
||||
#elif !defined(LFS_NO_INTRINSICS) && \
|
||||
((defined(BYTE_ORDER) && BYTE_ORDER == ORDER_BIG_ENDIAN) || (defined(__BYTE_ORDER) && __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \
|
||||
static inline uint32_t lfs_fromle32(uint32_t a)
|
||||
{
|
||||
#if !defined(LFS_NO_INTRINSICS) && ((defined(BYTE_ORDER) && BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \
|
||||
(defined(__BYTE_ORDER) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \
|
||||
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||
return a;
|
||||
#elif !defined(LFS_NO_INTRINSICS) && \
|
||||
((defined(BYTE_ORDER) && BYTE_ORDER == ORDER_BIG_ENDIAN) || (defined(__BYTE_ORDER) && __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \
|
||||
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
|
||||
return __builtin_bswap32(a);
|
||||
return __builtin_bswap32(a);
|
||||
#else
|
||||
return (((uint8_t *)&a)[0] << 0) | (((uint8_t *)&a)[1] << 8) | (((uint8_t *)&a)[2] << 16) | (((uint8_t *)&a)[3] << 24);
|
||||
return (((uint8_t *)&a)[0] << 0) | (((uint8_t *)&a)[1] << 8) | (((uint8_t *)&a)[2] << 16) | (((uint8_t *)&a)[3] << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Convert to 32-bit little-endian from native order
|
||||
static inline uint32_t lfs_tole32(uint32_t a) { return lfs_fromle32(a); }
|
||||
static inline uint32_t lfs_tole32(uint32_t a)
|
||||
{
|
||||
return lfs_fromle32(a);
|
||||
}
|
||||
|
||||
// Calculate CRC-32 with polynomial = 0x04c11db7
|
||||
void lfs_crc(uint32_t *crc, const void *buffer, size_t size);
|
||||
|
||||
// Allocate memory, only used if buffers are not provided to littlefs
|
||||
static inline void *lfs_malloc(size_t size) {
|
||||
static inline void *lfs_malloc(size_t size)
|
||||
{
|
||||
#ifndef LFS_NO_MALLOC
|
||||
return malloc(size);
|
||||
return malloc(size);
|
||||
#else
|
||||
(void)size;
|
||||
return NULL;
|
||||
(void)size;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Deallocate memory, only used if buffers are not provided to littlefs
|
||||
static inline void lfs_free(void *p) {
|
||||
static inline void lfs_free(void *p)
|
||||
{
|
||||
#ifndef LFS_NO_MALLOC
|
||||
free(p);
|
||||
free(p);
|
||||
#else
|
||||
(void)p;
|
||||
(void)p;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -9,19 +9,20 @@ void playStartMelody() {}
|
||||
|
||||
void updateBatteryLevel(uint8_t level) {}
|
||||
|
||||
void getMacAddr(uint8_t *dmac) {
|
||||
// https://flit.github.io/2020/06/06/mcu-unique-id-survey.html
|
||||
const uint32_t uid0 = HAL_GetUIDw0(); // X/Y coordinate on wafer
|
||||
const uint32_t uid1 = HAL_GetUIDw1(); // [31:8] Lot number (23:0), [7:0] Wafer number
|
||||
const uint32_t uid2 = HAL_GetUIDw2(); // Lot number (55:24)
|
||||
void getMacAddr(uint8_t *dmac)
|
||||
{
|
||||
// https://flit.github.io/2020/06/06/mcu-unique-id-survey.html
|
||||
const uint32_t uid0 = HAL_GetUIDw0(); // X/Y coordinate on wafer
|
||||
const uint32_t uid1 = HAL_GetUIDw1(); // [31:8] Lot number (23:0), [7:0] Wafer number
|
||||
const uint32_t uid2 = HAL_GetUIDw2(); // Lot number (55:24)
|
||||
|
||||
// Need to go from 96-bit to 48-bit unique ID
|
||||
dmac[5] = (uint8_t)uid0;
|
||||
dmac[4] = (uint8_t)(uid0 >> 16);
|
||||
dmac[3] = (uint8_t)uid1;
|
||||
dmac[2] = (uint8_t)(uid1 >> 8);
|
||||
dmac[1] = (uint8_t)uid2;
|
||||
dmac[0] = (uint8_t)(uid2 >> 8);
|
||||
// Need to go from 96-bit to 48-bit unique ID
|
||||
dmac[5] = (uint8_t)uid0;
|
||||
dmac[4] = (uint8_t)(uid0 >> 16);
|
||||
dmac[3] = (uint8_t)uid1;
|
||||
dmac[2] = (uint8_t)(uid1 >> 8);
|
||||
dmac[1] = (uint8_t)uid2;
|
||||
dmac[0] = (uint8_t)(uid2 >> 8);
|
||||
}
|
||||
|
||||
void cpuDeepSleep(uint32_t msecToWake) {}
|
||||
@@ -29,20 +30,27 @@ void cpuDeepSleep(uint32_t msecToWake) {}
|
||||
// Hacks to force more code and data out.
|
||||
|
||||
// By default __assert_func uses fiprintf which pulls in stdio.
|
||||
extern "C" void __wrap___assert_func(const char *, int, const char *, const char *) {
|
||||
while (true)
|
||||
;
|
||||
return;
|
||||
extern "C" void __wrap___assert_func(const char *, int, const char *, const char *)
|
||||
{
|
||||
while (true)
|
||||
;
|
||||
return;
|
||||
}
|
||||
|
||||
// By default strerror has a lot of strings we probably don't use. Make it return an empty string instead.
|
||||
char empty = 0;
|
||||
extern "C" char *__wrap_strerror(int) { return ∅ }
|
||||
extern "C" char *__wrap_strerror(int)
|
||||
{
|
||||
return ∅
|
||||
}
|
||||
|
||||
#ifdef MESHTASTIC_EXCLUDE_TZ
|
||||
struct _reent;
|
||||
|
||||
// Even if you don't use timezones, mktime will try to set the timezone anyway with _tzset_unlocked(), which pulls in
|
||||
// scanf and friends. The timezone is initialized to UTC by default.
|
||||
extern "C" void __wrap__tzset_unlocked_r(struct _reent *reent_ptr) { return; }
|
||||
// Even if you don't use timezones, mktime will try to set the timezone anyway with _tzset_unlocked(), which pulls in scanf and
|
||||
// friends. The timezone is initialized to UTC by default.
|
||||
extern "C" void __wrap__tzset_unlocked_r(struct _reent *reent_ptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user