diff --git a/README.md b/README.md index f1c3557..a673307 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ A low power soil moisture sensor based on the nRF52840. # TODO -* Implement BLE advertising with moisture, battery level +* Implement battery level monitoring * Figure out how to calibrate the ADC when running from different voltages, as the battery discharges +* Experiment with different TX power / battery tradeoff. Since we'll be deepsleeping most of the time, maybe we can get away with a lot of TX power. * Implement deep sleep * Measure current in deep sleep * Measure current in operation (ADC + BLE adversiting) @@ -15,6 +16,7 @@ A low power soil moisture sensor based on the nRF52840. * Design new board using the nrf52 instead of esp32 # Done +* Implement BLE advertising with moisture * Implement ADC for the parasitic capacitor; check out air/water range (using protoboard) * Simple PWM square wave generator * Hook square wave generator to the protoboard sensor circuit diff --git a/code/parasite/lib/parasite/parasite/ble.cpp b/code/parasite/lib/parasite/parasite/ble.cpp index 8ef29e1..b184167 100644 --- a/code/parasite/lib/parasite/parasite/ble.cpp +++ b/code/parasite/lib/parasite/parasite/ble.cpp @@ -1 +1,46 @@ -#include "ble.h" \ No newline at end of file +#include "ble.h" + +#include + +namespace parasite { +namespace {} + +void BLEAdvertiser::SetData(BLEAdvertisementData data) { + data_ = std::move(data); + if (is_running_) { + Bluefruit.Advertising.stop(); + } + Bluefruit.Advertising.clearData(); + Bluefruit.Advertising.setData(data_.GetRawData(), data_.GetDataLen()); + if (is_running_) { + Bluefruit.Advertising.start(0); + } +} + +void BLEAdvertiser::Init() { + ble_gap_addr_t addr; + addr.addr_id_peer = 1; + addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC; + std::copy(std::begin(mac_addr_), std::end(mac_addr_), std::begin(addr.addr)); + Bluefruit.begin(1, 1); + Bluefruit.setName("Parasite"); + Bluefruit.setAddr(&addr); + is_initialized_ = true; +} + +void BLEAdvertiser::Start() { + if (!is_initialized_) { + Init(); + } + 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 + is_running_ = true; +} + +void BLEAdvertiser::Stop() { + Bluefruit.Advertising.stop(); + is_running_ = false; +} + +} // namespace parasite \ No newline at end of file diff --git a/code/parasite/lib/parasite/parasite/ble.h b/code/parasite/lib/parasite/parasite/ble.h index 2c51365..5722e08 100644 --- a/code/parasite/lib/parasite/parasite/ble.h +++ b/code/parasite/lib/parasite/parasite/ble.h @@ -1,13 +1,29 @@ #ifndef _PARASITE_BLE_H_ #define _PARASITE_BLE_H_ +#include #include +#include "parasite/ble_advertisement_data.h" + namespace parasite { +using MACAddr = std::array; + class BLEAdvertiser { public: - void Advertise(std::string name, double moisture) {} + explicit BLEAdvertiser(MACAddr mac_addr) : mac_addr_(std::move(mac_addr)) {} + void SetData(BLEAdvertisementData data); + void Start(); + void Stop(); + bool IsRunning() const { return is_running_; }; + + private: + bool is_initialized_; + bool is_running_; + void Init(); + BLEAdvertisementData data_; + MACAddr mac_addr_; }; } // namespace parasite diff --git a/code/parasite/lib/parasite/parasite/ble_advertisement_data.cpp b/code/parasite/lib/parasite/parasite/ble_advertisement_data.cpp index 0d15dba..8f6fe63 100644 --- a/code/parasite/lib/parasite/parasite/ble_advertisement_data.cpp +++ b/code/parasite/lib/parasite/parasite/ble_advertisement_data.cpp @@ -8,4 +8,4 @@ void BLEAdvertisementData::SetRawSoilMoisture(int raw_soil_moisture) { data_[kRawSoilMoistureOffset + 1] = packed_value & 0xff; } -} \ No newline at end of file +} // namespace parasite \ No newline at end of file diff --git a/code/parasite/src/main.cpp b/code/parasite/src/main.cpp index c262a5f..e4521e1 100644 --- a/code/parasite/src/main.cpp +++ b/code/parasite/src/main.cpp @@ -1,7 +1,7 @@ #include -#include #include +#include #include "parasite/ble.h" #include "parasite/ble_advertisement_data.h" @@ -14,53 +14,44 @@ constexpr int kSensAnalogPin = 4; // AIN2 constexpr int kDischargeEnablePin = 16; constexpr double kPWMFrequency = 500000; -ble_gap_addr_t kGAPAddr{ - 1, - BLE_GAP_ADDR_TYPE_PUBLIC, - // This is the "reverse" order in comparison that the colon-separated - // human-readable MAC addresses. - {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, -}; +const parasite::MACAddr kMACAddr = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; +parasite::BLEAdvertiser advertiser(kMACAddr); -void setupAdvertising() { - Bluefruit.begin(1, 1); - Bluefruit.setName("Parasite"); - Bluefruit.setAddr(&kGAPAddr); -} - -void updateAdvertisingData(int moisture_level) { +void updateAdvertisingData(parasite::BLEAdvertiser *advertiser, + int moisture_level) { parasite::BLEAdvertisementData data; data.SetRawSoilMoisture(moisture_level); - Bluefruit.Advertising.stop(); - Bluefruit.Advertising.clearData(); - Bluefruit.Advertising.setData(data.GetRawData(), data.GetDataLen()); - 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 + + advertiser->SetData(data); + + if (!advertiser->IsRunning()) { + advertiser->Start(); + } } void setup() { Serial.begin(9600); + pinMode(kLED1Pin, OUTPUT); pinMode(kDischargeEnablePin, OUTPUT); + + // Activate the PWM signal. parasite::SetupSquareWave(kPWMFrequency, kPWMPin); + + // Enable fast discharge cycle. digitalWrite(kDischargeEnablePin, HIGH); + // We setup the analog reference to be VDD. This allows us to cancel out + // the effect of the battery discharge across time, since the RC circuit + // also depends linearly on VDD. + // TODO(rbaron): empirically prove/disprove this. analogReference(AR_VDD4); - - setupAdvertising(); - - Serial.println("Will advertise with MAC:"); - for (const auto byte : kGAPAddr.addr) { - Serial.printf("0x%02x ", byte); - } - Serial.println(); } void loop() { int sens_val = analogRead(kSensAnalogPin); Serial.printf("Val: %d\n", sens_val); digitalToggle(kLED1Pin); - updateAdvertisingData(sens_val); + updateAdvertisingData(&advertiser, sens_val); delay(500); -} +} \ No newline at end of file