mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-26 18:09:04 +00:00
Merge pull request #521 from meshtastic/master
Update dev-https from master
This commit is contained in:
commit
71d1d4d8fa
@ -1,3 +1,3 @@
|
||||
|
||||
|
||||
export VERSION=1.1.7
|
||||
export VERSION=1.1.8
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v6.ld"
|
||||
"ldscript": "nrf52840_s113_v7.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
@ -16,9 +16,9 @@
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_flags": "-DS140",
|
||||
"sd_name": "s140",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_flags": "-DS113",
|
||||
"sd_name": "s113",
|
||||
"sd_version": "7.2.0",
|
||||
"sd_fwid": "0x00B6"
|
||||
},
|
||||
"bootloader": {
|
||||
|
BIN
docs/hardware/pinetab/SX1302/DS_SX1302_V1.0.pdf
Normal file
BIN
docs/hardware/pinetab/SX1302/DS_SX1302_V1.0.pdf
Normal file
Binary file not shown.
BIN
docs/hardware/pinetab/SX1302/M-GW1302S 用户手册(2)(1)(1).pdf
Normal file
BIN
docs/hardware/pinetab/SX1302/M-GW1302S 用户手册(2)(1)(1).pdf
Normal file
Binary file not shown.
BIN
docs/hardware/pinetab/SX1302/M-GW1302S(射频版)硬件设计手册_V1.1.pdf
Normal file
BIN
docs/hardware/pinetab/SX1302/M-GW1302S(射频版)硬件设计手册_V1.1.pdf
Normal file
Binary file not shown.
BIN
docs/hardware/pinetab/SX1302/M-GW1302(透传版)_硬件设计手册.pdf
Normal file
BIN
docs/hardware/pinetab/SX1302/M-GW1302(透传版)_硬件设计手册.pdf
Normal file
Binary file not shown.
@ -2,15 +2,11 @@
|
||||
|
||||
You probably don't care about this section - skip to the next one.
|
||||
|
||||
Threading tasks:
|
||||
For high speed/lots of devices/short range tasks:
|
||||
|
||||
- Use https://github.com/ivanseidel/ArduinoThread? rather than full coroutines
|
||||
- clean up main loop()
|
||||
- check that we are mostly asleep, show which thread is causing us to wake
|
||||
-
|
||||
- use tickless idle on nrf52, and sleep X msec or until an interrupt occurs or the cooperative scheduling changes. https://devzone.nordicsemi.com/f/nordic-q-a/12363/nrf52-freertos-power-consumption-tickless-idle
|
||||
- BAD IDEA: use vTaskDelay and https://www.freertos.org/xTaskAbortDelay.html if scheduling changes. (define INCLUDE_xTaskAbortDelay on ESP32 and NRF52 - seems impossible to find?)
|
||||
- GOOD IDEA: use xSemaphoreTake to take a semaphore using a timeout. Expect semaphore to not be set, but set it to indicate scheduling has changed.
|
||||
- When guessing numhops for sending: if I've heard from many local (0 hop neighbors) decrease hopcount by 2 rather than 1.
|
||||
This should nicely help 'router' nodes do the right thing when long range, or if there are many local nodes for short range.
|
||||
- fix timeouts/delays to be based on packet length at current radio settings
|
||||
|
||||
Nimble tasks:
|
||||
|
||||
|
@ -14,6 +14,13 @@ Notes here on using that driver: https://www.linuxquestions.org/questions/linux-
|
||||
|
||||
Or if **absolutely** necessary could bitbang: https://www.cnx-software.com/2018/02/16/wch-ch341-usb-to-serial-chip-gets-linux-driver-to-control-gpios-over-usb/
|
||||
|
||||
## Portduino tasks
|
||||
|
||||
* How to access spi devices via ioctl (spidev): https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md#:~:text=Troubleshooting-,Overview,bus)%2C%20UARTs%2C%20etc.
|
||||
* access gpio via libgpiod?
|
||||
* Use dkms to distribute driver?
|
||||
* echo 100 > /sys/module/spi_ch341_usb/parameters/poll_period
|
||||
|
||||
## Task list
|
||||
|
||||
* Port meshtastic to build (under platformio) for a poxix target. spec: no screen, no gpios, sim network interface, posix threads, posix semaphores & queues, IO to the console only
|
||||
|
@ -251,13 +251,11 @@ void PowerFSM_setup()
|
||||
#ifndef NRF52_SERIES
|
||||
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
|
||||
|
||||
lowPowerState = &stateDARK;
|
||||
|
||||
powerFSM.add_timed_transition(&stateDARK, &stateNB, getPref_phone_timeout_secs() * 1000, NULL, "Phone timeout");
|
||||
|
||||
powerFSM.add_timed_transition(&stateNB, &stateLS, getPref_min_wake_secs() * 1000, NULL, "Min wake timeout");
|
||||
|
||||
powerFSM.add_timed_transition(&stateDARK, &stateLS, getPref_wait_bluetooth_secs() * 1000, NULL, "Bluetooth timeout");
|
||||
#else
|
||||
lowPowerState = &stateDARK;
|
||||
#endif
|
||||
|
||||
auto meshSds = getPref_mesh_sds_timeout_secs();
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "RedirectablePrint.h"
|
||||
#include "configuration.h"
|
||||
#include <assert.h>
|
||||
|
||||
/**
|
||||
@ -11,3 +12,13 @@ void RedirectablePrint::setDestination(Print *_dest)
|
||||
assert(_dest);
|
||||
dest = _dest;
|
||||
}
|
||||
|
||||
size_t RedirectablePrint::write(uint8_t c)
|
||||
{
|
||||
#ifdef SEGGER_STDOUT_CH
|
||||
SEGGER_RTT_PutCharSkip(SEGGER_STDOUT_CH, c);
|
||||
#endif
|
||||
|
||||
dest->write(c);
|
||||
return 1; // We always claim one was written, rather than trusting what the serial port said (which could be zero)
|
||||
}
|
@ -19,7 +19,7 @@ class RedirectablePrint : public Print
|
||||
*/
|
||||
void setDestination(Print *dest);
|
||||
|
||||
virtual size_t write(uint8_t c) { return dest->write(c); }
|
||||
virtual size_t write(uint8_t c);
|
||||
};
|
||||
|
||||
class NoopPrint : public Print
|
||||
|
@ -404,8 +404,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// Always include the SEGGER code on NRF52 - because useful for debugging
|
||||
#include "SEGGER_RTT.h"
|
||||
|
||||
// The channel we send stdout data to
|
||||
#define SEGGER_STDOUT_CH 0
|
||||
|
||||
// Debug printing to segger console
|
||||
#define SEGGER_MSG(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||
#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
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "utils.h"
|
||||
#include <nvs.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
void getMacAddr(uint8_t *dmac)
|
||||
{
|
||||
@ -87,3 +88,57 @@ void esp32Loop()
|
||||
// for debug printing
|
||||
// radio.radioIf.canSleep();
|
||||
}
|
||||
|
||||
void cpuDeepSleep(uint64_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.
|
||||
|
||||
Note: we don't isolate pins that are used for the LORA, LED, i2c, spi or the wake button
|
||||
*/
|
||||
static const uint8_t rtcGpios[] = {/* 0, */ 2,
|
||||
/* 4, */
|
||||
#ifndef USE_JTAG
|
||||
13,
|
||||
/* 14, */ /* 15, */
|
||||
#endif
|
||||
/* 25, */ 26, /* 27, */
|
||||
32, 33, 34, 35,
|
||||
36, 37
|
||||
/* 38, 39 */};
|
||||
|
||||
for (int i = 0; i < sizeof(rtcGpios); i++)
|
||||
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
|
||||
|
||||
// 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.
|
||||
|
||||
// We want RTC peripherals to stay on
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
#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.
|
||||
uint64_t gpioMask = (1ULL << BUTTON_PIN);
|
||||
|
||||
#ifdef BUTTON_NEED_PULLUP
|
||||
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);
|
||||
|
||||
esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ALL_LOW);
|
||||
#endif
|
||||
|
||||
esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
|
||||
esp_deep_sleep_start(); // TBD mA sleep current (battery)
|
||||
}
|
@ -25,9 +25,15 @@ uint8_t GPS::i2cAddress = 0;
|
||||
|
||||
GPS *gps;
|
||||
|
||||
/// Multiple GPS instances might use the same serial port (in sequence), but we can
|
||||
/// only init that port once.
|
||||
static bool didSerialInit;
|
||||
|
||||
bool GPS::setupGPS()
|
||||
{
|
||||
if (_serial_gps) {
|
||||
if (_serial_gps && !didSerialInit) {
|
||||
didSerialInit = true;
|
||||
|
||||
#ifdef GPS_RX_PIN
|
||||
_serial_gps->begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
|
||||
#else
|
||||
@ -59,8 +65,10 @@ bool GPS::setup()
|
||||
setAwake(true); // Wake GPS power before doing any init
|
||||
bool ok = setupGPS();
|
||||
|
||||
if (ok)
|
||||
if (ok) {
|
||||
notifySleepObserver.observe(¬ifySleep);
|
||||
notifyDeepSleepObserver.observe(¬ifyDeepSleep);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
@ -275,7 +283,19 @@ void GPS::forceWake(bool on)
|
||||
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
||||
int GPS::prepareSleep(void *unused)
|
||||
{
|
||||
DEBUG_MSG("GPS prepare sleep!\n");
|
||||
forceWake(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
|
||||
int GPS::prepareDeepSleep(void *unused)
|
||||
{
|
||||
DEBUG_MSG("GPS deep sleep!\n");
|
||||
|
||||
// For deep sleep we also want abandon any lock attempts (because we want minimum power)
|
||||
setAwake(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ class GPS : private concurrency::OSThread
|
||||
uint8_t numSatellites = 0;
|
||||
|
||||
CallbackObserver<GPS, void *> notifySleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareSleep);
|
||||
CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
|
||||
|
||||
public:
|
||||
/** If !NULL we will use this serial port to construct our GPS */
|
||||
@ -115,6 +116,10 @@ class GPS : private concurrency::OSThread
|
||||
/// always returns 0 to indicate okay to sleep
|
||||
int prepareSleep(void *unused);
|
||||
|
||||
/// Prepare the GPS for the cpu entering deep sleep, expect to be gone for at least 100s of msecs
|
||||
/// always returns 0 to indicate okay to sleep
|
||||
int prepareDeepSleep(void *unused);
|
||||
|
||||
/**
|
||||
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
|
||||
*
|
||||
|
@ -85,13 +85,16 @@ static uint16_t displayWidth, displayHeight;
|
||||
#define SCREEN_TRANSITION_MSECS 300
|
||||
#endif
|
||||
|
||||
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
/**
|
||||
* Draw the icon with extra info printed around the corners
|
||||
*/
|
||||
static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// draw an xbm image.
|
||||
// Please note that everything that should be transitioned
|
||||
// needs to be drawn relative to x and y
|
||||
|
||||
// draw centered left to right and centered above the one line of app text
|
||||
// draw centered icon left to right and centered above the one line of app text
|
||||
display->drawXbm(x + (SCREEN_WIDTH - icon_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - icon_height) / 2 + 2,
|
||||
icon_width, icon_height, (const uint8_t *)icon_bits);
|
||||
|
||||
@ -101,15 +104,31 @@ static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
||||
display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title);
|
||||
display->setFont(FONT_SMALL);
|
||||
|
||||
const char *region = myRegion ? myRegion->name : NULL;
|
||||
if (region)
|
||||
display->drawString(x + 0, y + 0, region);
|
||||
// Draw region in upper left
|
||||
if (upperMsg)
|
||||
display->drawString(x + 0, y + 0, upperMsg);
|
||||
|
||||
// Draw version in upper right
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "%s",
|
||||
xstr(APP_VERSION)); // Note: we don't bother printing region or now, it makes the string too long
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf);
|
||||
screen->forceDisplay();
|
||||
|
||||
// FIXME - draw serial # somewhere?
|
||||
}
|
||||
|
||||
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
// Draw region in upper left
|
||||
const char *region = myRegion ? myRegion->name : NULL;
|
||||
drawIconScreen(region, display, state, x, y);
|
||||
}
|
||||
|
||||
/// Used on eink displays while in deep sleep
|
||||
static void drawSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
drawIconScreen("Sleeping...", display, state, x, y);
|
||||
}
|
||||
|
||||
static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
@ -600,6 +619,21 @@ Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue
|
||||
cmdQueue.setReader(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the display for the unit going to the lowest power mode possible. Most screens will just
|
||||
* poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code
|
||||
*/
|
||||
void Screen::doDeepSleep()
|
||||
{
|
||||
#ifdef HAS_EINK
|
||||
static FrameCallback sleepFrames[] = {drawSleepScreen};
|
||||
static const int sleepFrameCount = sizeof(sleepFrames) / sizeof(sleepFrames[0]);
|
||||
ui.setFrames(sleepFrames, sleepFrameCount);
|
||||
ui.update();
|
||||
#endif
|
||||
setOn(false);
|
||||
}
|
||||
|
||||
void Screen::handleSetOn(bool on)
|
||||
{
|
||||
if (!useDisplay)
|
||||
|
@ -99,6 +99,12 @@ class Screen : public concurrency::OSThread
|
||||
enqueueCmd(ScreenCmd{.cmd = on ? Cmd::SET_ON : Cmd::SET_OFF});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the display for the unit going to the lowest power mode possible. Most screens will just
|
||||
* poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code
|
||||
*/
|
||||
void doDeepSleep();
|
||||
|
||||
/// Handles a button press.
|
||||
void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); }
|
||||
|
||||
|
12
src/main.cpp
12
src/main.cpp
@ -172,6 +172,10 @@ class ButtonThread : public OSThread
|
||||
{
|
||||
#ifdef BUTTON_PIN
|
||||
userButton = OneButton(BUTTON_PIN, true, true);
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||
pinMode(BUTTON_PIN, INPUT_PULLUP_SENSE);
|
||||
#endif
|
||||
userButton.attachClick(userButtonPressed);
|
||||
userButton.attachDuringLongPress(userButtonPressedLong);
|
||||
userButton.attachDoubleClick(userButtonDoublePressed);
|
||||
@ -179,6 +183,10 @@ class ButtonThread : public OSThread
|
||||
#endif
|
||||
#ifdef BUTTON_PIN_ALT
|
||||
userButtonAlt = OneButton(BUTTON_PIN_ALT, true, true);
|
||||
#ifdef INPUT_PULLUP_SENSE
|
||||
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
|
||||
pinMode(BUTTON_PIN_ALT, INPUT_PULLUP_SENSE);
|
||||
#endif
|
||||
userButtonAlt.attachClick(userButtonPressed);
|
||||
userButtonAlt.attachDuringLongPress(userButtonPressedLong);
|
||||
userButtonAlt.attachDoubleClick(userButtonDoublePressed);
|
||||
@ -233,8 +241,8 @@ RadioInterface *rIf = NULL;
|
||||
|
||||
void setup()
|
||||
{
|
||||
#ifdef USE_SEGGER
|
||||
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
|
||||
#ifdef SEGGER_STDOUT_CH
|
||||
SEGGER_RTT_ConfigUpBuffer(SEGGER_STDOUT_CH, NULL, NULL, 1024, SEGGER_RTT_MODE_NO_BLOCK_TRIM);
|
||||
#endif
|
||||
|
||||
// Debug
|
||||
|
@ -143,11 +143,15 @@ bool NodeDB::resetRadioConfig()
|
||||
DEBUG_MSG("***** DEVELOPMENT MODE - DO NOT RELEASE *****\n");
|
||||
|
||||
// Sleep quite frequently to stress test the BLE comms, broadcast position every 6 mins
|
||||
radioConfig.preferences.screen_on_secs = 30;
|
||||
radioConfig.preferences.wait_bluetooth_secs = 30;
|
||||
radioConfig.preferences.screen_on_secs = 10;
|
||||
radioConfig.preferences.wait_bluetooth_secs = 10;
|
||||
radioConfig.preferences.position_broadcast_secs = 6 * 60;
|
||||
radioConfig.preferences.ls_secs = 60;
|
||||
radioConfig.preferences.region = RegionCode_TW;
|
||||
|
||||
// Enter super deep sleep soon and stay there not very long
|
||||
//radioConfig.preferences.mesh_sds_timeout_secs = 10;
|
||||
//radioConfig.preferences.sds_secs = 60;
|
||||
}
|
||||
|
||||
// Update the global myRegion
|
||||
|
@ -53,6 +53,68 @@ separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts
|
||||
// 1kb was too small
|
||||
#define RADIO_STACK_SIZE 4096
|
||||
|
||||
/**
|
||||
* Calculate airtime per
|
||||
* https://www.rs-online.com/designspark/rel-assets/ds-assets/uploads/knowledge-items/application-notes-for-the-internet-of-things/LoRa%20Design%20Guide.pdf
|
||||
* section 4
|
||||
*
|
||||
* @return num msecs for the packet
|
||||
*/
|
||||
uint32_t RadioInterface::getPacketTime(uint32_t pl)
|
||||
{
|
||||
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
|
||||
|
||||
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;
|
||||
|
||||
DEBUG_MSG("(bw=%d, sf=%d, cr=4/%d) packet symLen=%d ms, payloadSize=%u, time %d ms\n", (int)bw, sf, cr, (int)(tSym * 1000),
|
||||
pl, msecs);
|
||||
return msecs;
|
||||
}
|
||||
|
||||
uint32_t RadioInterface::getPacketTime(MeshPacket *p)
|
||||
{
|
||||
assert(p->which_payload == MeshPacket_encrypted_tag); // It should have already been encoded by now
|
||||
uint32_t pl = p->encrypted.size + sizeof(PacketHeader);
|
||||
|
||||
return getPacketTime(pl);
|
||||
}
|
||||
|
||||
/** The delay to use for retransmitting dropped packets */
|
||||
uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
|
||||
{
|
||||
// was 20 and 22 secs respectively, but now with shortPacketMsec as 2269, this should give the same range
|
||||
return random(9 * shortPacketMsec, 10 * shortPacketMsec);
|
||||
}
|
||||
|
||||
/** The delay to use when we want to send something but the ether is busy */
|
||||
uint32_t RadioInterface::getTxDelayMsec()
|
||||
{
|
||||
/** At the low end we want to pick a delay large enough that anyone who just completed sending (some other node)
|
||||
* has had enough time to switch their radio back into receive mode.
|
||||
*/
|
||||
const uint32_t MIN_TX_WAIT_MSEC = 100;
|
||||
|
||||
/**
|
||||
* At the high end, this value is used to spread node attempts across time so when they are replying to a packet
|
||||
* they don't both check that the airwaves are clear at the same moment. As long as they are off by some amount
|
||||
* one of the two will be first to start transmitting and the other will see that. I bet 500ms is more than enough
|
||||
* to guarantee this.
|
||||
*/
|
||||
// const uint32_t MAX_TX_WAIT_MSEC = 2000; // stress test would still fail occasionally with 1000
|
||||
|
||||
return random(MIN_TX_WAIT_MSEC, shortPacketMsec);
|
||||
}
|
||||
|
||||
void printPacket(const char *prefix, const MeshPacket *p)
|
||||
{
|
||||
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack,
|
||||
@ -125,6 +187,12 @@ bool RadioInterface::init()
|
||||
return true;
|
||||
}
|
||||
|
||||
int RadioInterface::notifyDeepSleepCb(void *unused)
|
||||
{
|
||||
sleep();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** hash a string into an integer
|
||||
*
|
||||
* djb2 by Dan Bernstein.
|
||||
@ -149,8 +217,47 @@ void RadioInterface::applyModemConfig()
|
||||
// Set up default configuration
|
||||
// No Sync Words in LORA mode
|
||||
|
||||
if (channelSettings.spread_factor == 0) {
|
||||
switch (channelSettings.modem_config) {
|
||||
case ChannelSettings_ModemConfig_Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium
|
||||
///< range
|
||||
bw = 125;
|
||||
cr = 5;
|
||||
sf = 7;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short
|
||||
///< range
|
||||
bw = 500;
|
||||
cr = 5;
|
||||
sf = 7;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long
|
||||
///< range
|
||||
bw = 31.25;
|
||||
cr = 8;
|
||||
sf = 9;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
|
||||
bw = 125;
|
||||
cr = 8;
|
||||
sf = 12;
|
||||
break;
|
||||
default:
|
||||
assert(0); // Unknown enum
|
||||
}
|
||||
} else {
|
||||
sf = channelSettings.spread_factor;
|
||||
cr = channelSettings.coding_rate;
|
||||
bw = channelSettings.bandwidth;
|
||||
|
||||
if (bw == 31) // This parameter is not an integer
|
||||
bw = 31.25;
|
||||
}
|
||||
|
||||
power = channelSettings.tx_power;
|
||||
|
||||
shortPacketMsec = getPacketTime(sizeof(PacketHeader));
|
||||
|
||||
assert(myRegion); // Should have been found in init
|
||||
|
||||
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
|
||||
@ -165,6 +272,7 @@ void RadioInterface::applyModemConfig()
|
||||
DEBUG_MSG("Radio myRegion->numChannels: %d\n", myRegion->numChannels);
|
||||
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
|
||||
DEBUG_MSG("Radio frequency: %f\n", freq);
|
||||
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,9 +48,18 @@ class RadioInterface
|
||||
CallbackObserver<RadioInterface, void *>(this, &RadioInterface::preflightSleepCb);
|
||||
|
||||
CallbackObserver<RadioInterface, void *> notifyDeepSleepObserver =
|
||||
CallbackObserver<RadioInterface, void *>(this, &RadioInterface::notifyDeepSleepDb);
|
||||
CallbackObserver<RadioInterface, void *>(this, &RadioInterface::notifyDeepSleepCb);
|
||||
|
||||
/// Number of msecs we expect our shortest actual packet to be over the wire (used in retry timeout calcs)
|
||||
uint32_t shortPacketMsec;
|
||||
|
||||
protected:
|
||||
float bw = 125;
|
||||
uint8_t sf = 9;
|
||||
uint8_t cr = 7;
|
||||
|
||||
uint16_t preambleLength = 32; // 8 is default, but FIXME use longer to increase the amount of sleep time when receiving
|
||||
|
||||
MeshPacket *sendingPacket = NULL; // The packet we are currently sending
|
||||
uint32_t lastTxStart = 0L;
|
||||
|
||||
@ -108,6 +117,22 @@ class RadioInterface
|
||||
/// \return true if initialisation succeeded.
|
||||
virtual bool reconfigure() = 0;
|
||||
|
||||
/** The delay to use for retransmitting dropped packets */
|
||||
uint32_t getRetransmissionMsec(const MeshPacket *p);
|
||||
|
||||
/** The delay to use when we want to send something but the ether is busy */
|
||||
uint32_t getTxDelayMsec();
|
||||
|
||||
/**
|
||||
* Calculate airtime per
|
||||
* https://www.rs-online.com/designspark/rel-assets/ds-assets/uploads/knowledge-items/application-notes-for-the-internet-of-things/LoRa%20Design%20Guide.pdf
|
||||
* section 4
|
||||
*
|
||||
* @return num msecs for the packet
|
||||
*/
|
||||
uint32_t getPacketTime(MeshPacket *p);
|
||||
uint32_t getPacketTime(uint32_t totalPacketLen);
|
||||
|
||||
protected:
|
||||
int8_t power = 17; // Set by applyModemConfig()
|
||||
|
||||
@ -136,11 +161,7 @@ class RadioInterface
|
||||
/// Return 0 if sleep is okay
|
||||
int preflightSleepCb(void *unused = NULL) { return canSleep() ? 0 : 1; }
|
||||
|
||||
int notifyDeepSleepDb(void *unused = NULL)
|
||||
{
|
||||
sleep();
|
||||
return 0;
|
||||
}
|
||||
int notifyDeepSleepCb(void *unused = NULL);
|
||||
|
||||
int reloadConfig(void *unused)
|
||||
{
|
||||
|
@ -58,50 +58,6 @@ void INTERRUPT_ATTR RadioLibInterface::isrTxLevel0()
|
||||
*/
|
||||
RadioLibInterface *RadioLibInterface::instance;
|
||||
|
||||
/**
|
||||
* Convert our modemConfig enum into wf, sf, etc...
|
||||
*/
|
||||
void RadioLibInterface::applyModemConfig()
|
||||
{
|
||||
RadioInterface::applyModemConfig();
|
||||
|
||||
if (channelSettings.spread_factor == 0) {
|
||||
switch (channelSettings.modem_config) {
|
||||
case ChannelSettings_ModemConfig_Bw125Cr45Sf128: ///< Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Default medium
|
||||
///< range
|
||||
bw = 125;
|
||||
cr = 5;
|
||||
sf = 7;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw500Cr45Sf128: ///< Bw = 500 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on. Fast+short
|
||||
///< range
|
||||
bw = 500;
|
||||
cr = 5;
|
||||
sf = 7;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw31_25Cr48Sf512: ///< Bw = 31.25 kHz, Cr = 4/8, Sf = 512chips/symbol, CRC on. Slow+long
|
||||
///< range
|
||||
bw = 31.25;
|
||||
cr = 8;
|
||||
sf = 9;
|
||||
break;
|
||||
case ChannelSettings_ModemConfig_Bw125Cr48Sf4096:
|
||||
bw = 125;
|
||||
cr = 8;
|
||||
sf = 12;
|
||||
break;
|
||||
default:
|
||||
assert(0); // Unknown enum
|
||||
}
|
||||
} else {
|
||||
sf = channelSettings.spread_factor;
|
||||
cr = channelSettings.coding_rate;
|
||||
bw = channelSettings.bandwidth;
|
||||
|
||||
if (bw == 31) // This parameter is not an integer
|
||||
bw = 31.25;
|
||||
}
|
||||
}
|
||||
|
||||
/** Could we send right now (i.e. either not actively receving or transmitting)? */
|
||||
bool RadioLibInterface::canSendImmediately()
|
||||
@ -130,6 +86,8 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||
// Sometimes when testing it is useful to be able to never turn on the xmitter
|
||||
#ifndef LORA_DISABLE_SENDING
|
||||
printPacket("enqueuing for send", p);
|
||||
uint32_t xmitMsec = getPacketTime(p);
|
||||
|
||||
DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
|
||||
ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||
|
||||
@ -158,19 +116,6 @@ bool RadioLibInterface::canSleep()
|
||||
return res;
|
||||
}
|
||||
|
||||
/** At the low end we want to pick a delay large enough that anyone who just completed sending (some other node)
|
||||
* has had enough time to switch their radio back into receive mode.
|
||||
*/
|
||||
#define MIN_TX_WAIT_MSEC 100
|
||||
|
||||
/**
|
||||
* At the high end, this value is used to spread node attempts across time so when they are replying to a packet
|
||||
* they don't both check that the airwaves are clear at the same moment. As long as they are off by some amount
|
||||
* one of the two will be first to start transmitting and the other will see that. I bet 500ms is more than enough
|
||||
* to guarantee this.
|
||||
*/
|
||||
#define MAX_TX_WAIT_MSEC 2000 // stress test would still fail occasionally with 1000
|
||||
|
||||
/** radio helper thread callback.
|
||||
|
||||
We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and
|
||||
@ -226,8 +171,7 @@ void RadioLibInterface::startTransmitTimer(bool withDelay)
|
||||
{
|
||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||
if (!txQueue.isEmpty()) {
|
||||
uint32_t delay =
|
||||
!withDelay ? 1 : random(MIN_TX_WAIT_MSEC, MAX_TX_WAIT_MSEC); // See documentation for loop() wrt these values
|
||||
uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
|
||||
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
|
||||
}
|
||||
@ -236,20 +180,25 @@ void RadioLibInterface::startTransmitTimer(bool withDelay)
|
||||
void RadioLibInterface::handleTransmitInterrupt()
|
||||
{
|
||||
// DEBUG_MSG("handling lora TX interrupt\n");
|
||||
assert(sendingPacket); // Were we sending? - FIXME, this was null coming out of light sleep due to RF95 ISR!
|
||||
|
||||
completeSending();
|
||||
// This can be null if we forced the device to enter standby mode. In that case
|
||||
// ignore the transmit interrupt
|
||||
if (sendingPacket)
|
||||
completeSending();
|
||||
}
|
||||
|
||||
void RadioLibInterface::completeSending()
|
||||
{
|
||||
if (sendingPacket) {
|
||||
// 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++;
|
||||
printPacket("Completed sending", sendingPacket);
|
||||
printPacket("Completed sending", p);
|
||||
|
||||
// We are done sending that packet, release it
|
||||
packetPool.release(sendingPacket);
|
||||
sendingPacket = NULL;
|
||||
packetPool.release(p);
|
||||
// DEBUG_MSG("Done with send\n");
|
||||
}
|
||||
}
|
||||
@ -295,7 +244,7 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
addReceiveMetadata(mp);
|
||||
|
||||
mp->which_payload = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
|
||||
assert(payloadLen <= sizeof(mp->encrypted.bytes));
|
||||
assert(((uint32_t) payloadLen) <= sizeof(mp->encrypted.bytes));
|
||||
memcpy(mp->encrypted.bytes, payload, payloadLen);
|
||||
mp->encrypted.size = payloadLen;
|
||||
|
||||
|
@ -77,9 +77,6 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
PointerQueue<MeshPacket> txQueue = PointerQueue<MeshPacket>(MAX_TX_QUEUE);
|
||||
|
||||
protected:
|
||||
float bw = 125;
|
||||
uint8_t sf = 9;
|
||||
uint8_t cr = 7;
|
||||
|
||||
/**
|
||||
* FIXME, use a meshtastic sync word, but hashed with the Channel name. Currently picking the same default
|
||||
@ -88,7 +85,6 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
uint8_t syncWord = SX126X_SYNC_WORD_PRIVATE;
|
||||
|
||||
float currentLimit = 100; // FIXME
|
||||
uint16_t preambleLength = 32; // 8 is default, but FIXME use longer to increase the amount of sleep time when receiving
|
||||
|
||||
LockingModule module; // The HW interface to the radio
|
||||
|
||||
@ -165,13 +161,6 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
||||
/** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */
|
||||
virtual void configHardwareForSend() {}
|
||||
|
||||
/**
|
||||
* Convert our modemConfig enum into wf, sf, etc...
|
||||
*
|
||||
* These paramaters will be pull from the channelSettings global
|
||||
*/
|
||||
virtual void applyModemConfig();
|
||||
|
||||
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
||||
virtual bool canSendImmediately();
|
||||
|
||||
|
@ -111,7 +111,6 @@ PendingPacket::PendingPacket(MeshPacket *p)
|
||||
{
|
||||
packet = p;
|
||||
numRetransmissions = NUM_RETRANSMISSIONS - 1; // We subtract one, because we assume the user just did the first send
|
||||
setNextTx();
|
||||
}
|
||||
|
||||
PendingPacket *ReliableRouter::findPendingPacket(GlobalPacketId key)
|
||||
@ -151,6 +150,7 @@ PendingPacket *ReliableRouter::startRetransmission(MeshPacket *p)
|
||||
auto id = GlobalPacketId(p);
|
||||
auto rec = PendingPacket(p);
|
||||
|
||||
setNextTx(&rec);
|
||||
stopRetransmission(p->from, p->id);
|
||||
pending[id] = rec;
|
||||
|
||||
@ -190,10 +190,9 @@ int32_t ReliableRouter::doRetransmissions()
|
||||
|
||||
// Queue again
|
||||
--p.numRetransmissions;
|
||||
p.setNextTx();
|
||||
setNextTx(&p);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Not yet time
|
||||
int32_t t = p.nextTxMsec - now;
|
||||
|
||||
|
@ -46,8 +46,6 @@ struct PendingPacket {
|
||||
|
||||
PendingPacket() {}
|
||||
PendingPacket(MeshPacket *p);
|
||||
|
||||
void setNextTx() { nextTxMsec = millis() + random(20 * 1000L, 22 * 1000L); }
|
||||
};
|
||||
|
||||
class GlobalPacketIdHashFunction
|
||||
@ -130,4 +128,8 @@ class ReliableRouter : public FloodingRouter
|
||||
* @return the number of msecs until our next retransmission or MAXINT if none scheduled
|
||||
*/
|
||||
int32_t doRetransmissions();
|
||||
|
||||
void setNextTx(PendingPacket *pending) {
|
||||
assert(iface);
|
||||
pending->nextTxMsec = millis() + iface->getRetransmissionMsec(pending->packet); }
|
||||
};
|
||||
|
@ -14,12 +14,13 @@
|
||||
class Router : protected concurrency::OSThread
|
||||
{
|
||||
private:
|
||||
RadioInterface *iface;
|
||||
|
||||
/// Packets which have just arrived from the radio, ready to be processed by this service and possibly
|
||||
/// forwarded to the phone.
|
||||
PointerQueue<MeshPacket> fromRadioQueue;
|
||||
|
||||
protected:
|
||||
RadioInterface *iface = NULL;
|
||||
|
||||
public:
|
||||
/// Local services that want to see _every_ packet this node receives can observe this.
|
||||
/// Observers should always return 0 and _copy_ any packets they want to keep for use later (this packet will be getting
|
||||
|
@ -201,9 +201,21 @@ bool SX1262Interface::isActivelyReceiving()
|
||||
|
||||
bool SX1262Interface::sleep()
|
||||
{
|
||||
// put chipset into sleep mode
|
||||
disableInterrupt();
|
||||
lora.sleep();
|
||||
// Not keeping config is busted - next time nrf52 board boots lora sending fails tcxo related? - see datasheet
|
||||
DEBUG_MSG("sx1262 entering sleep mode (FIXME, don't keep config)\n");
|
||||
setStandby(); // Stop any pending operations
|
||||
|
||||
// turn off TCXO if it was powered
|
||||
// FIXME - this isn't correct
|
||||
// lora.setTCXO(0);
|
||||
|
||||
// put chipset into sleep mode (we've already disabled interrupts by now)
|
||||
bool keepConfig = true;
|
||||
lora.sleep(keepConfig); // Note: we do not keep the config, full reinit will be needed
|
||||
|
||||
#ifdef SX1262_POWER_EN
|
||||
digitalWrite(SX1262_POWER_EN, LOW);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
@ -202,6 +202,13 @@ void setupMeshService(void)
|
||||
// FIXME, turn off soft device access for debugging
|
||||
static bool isSoftDeviceAllowed = true;
|
||||
|
||||
void NRF52Bluetooth::shutdown()
|
||||
{
|
||||
// Shutdown bluetooth for minimum power draw
|
||||
DEBUG_MSG("Disable NRF52 bluetooth\n");
|
||||
Bluefruit.Advertising.stop();
|
||||
}
|
||||
|
||||
void NRF52Bluetooth::setup()
|
||||
{
|
||||
// Initialise the Bluefruit module
|
||||
|
@ -4,5 +4,6 @@ class NRF52Bluetooth
|
||||
{
|
||||
public:
|
||||
void setup();
|
||||
void shutdown();
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "NRF52Bluetooth.h"
|
||||
#include "configuration.h"
|
||||
#include "graphics/TFTDisplay.h"
|
||||
#include <SPI.h>
|
||||
#include <Wire.h>
|
||||
#include <assert.h>
|
||||
#include <ble_gap.h>
|
||||
#include <memory.h>
|
||||
@ -49,7 +51,7 @@ void getMacAddr(uint8_t *dmac)
|
||||
NRF52Bluetooth *nrf52Bluetooth;
|
||||
|
||||
static bool bleOn = false;
|
||||
static const bool enableBle = true; // Set to false for easier debugging
|
||||
static const bool enableBle = false; // Set to false for easier debugging
|
||||
|
||||
void setBluetoothEnable(bool on)
|
||||
{
|
||||
@ -64,7 +66,8 @@ void setBluetoothEnable(bool on)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG("FIXME: implement BLE disable\n");
|
||||
if (nrf52Bluetooth)
|
||||
nrf52Bluetooth->shutdown();
|
||||
}
|
||||
bleOn = on;
|
||||
}
|
||||
@ -97,7 +100,7 @@ void nrf52Setup()
|
||||
|
||||
#ifdef BQ25703A_ADDR
|
||||
auto *bq = new BQ25713();
|
||||
if(!bq->setup())
|
||||
if (!bq->setup())
|
||||
DEBUG_MSG("ERROR! Charge controller init failed\n");
|
||||
#endif
|
||||
|
||||
@ -110,3 +113,29 @@ void nrf52Setup()
|
||||
DEBUG_MSG("FIXME, call randomSeed\n");
|
||||
// ::printf("TESTING PRINTF\n");
|
||||
}
|
||||
|
||||
void cpuDeepSleep(uint64_t msecToWake)
|
||||
{
|
||||
// FIXME, configure RTC or button press to wake us
|
||||
// FIXME, power down SPI, I2C, RAMs
|
||||
Wire.end();
|
||||
SPI.end();
|
||||
Serial.end();
|
||||
Serial1.end();
|
||||
|
||||
// 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
|
||||
|
||||
auto ok = sd_power_system_off();
|
||||
if(ok != NRF_SUCCESS) {
|
||||
DEBUG_MSG("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!\n");
|
||||
NRF_POWER->SYSTEMOFF = 1;
|
||||
}
|
||||
|
||||
// The following code should not be run, because we are off
|
||||
while (1) {
|
||||
delay(5000);
|
||||
DEBUG_MSG(".");
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#include "CryptoEngine.h"
|
||||
#include "target_specific.h"
|
||||
#include <Utility.h>
|
||||
#include "sleep.h"
|
||||
|
||||
// FIXME - move getMacAddr/setBluetoothEnable into a HALPlatform class
|
||||
|
||||
@ -26,6 +27,10 @@ void setBluetoothEnable(bool on)
|
||||
notImplemented("setBluetoothEnable");
|
||||
}
|
||||
|
||||
void cpuDeepSleep(uint64_t msecs) {
|
||||
notImplemented("cpuDeepSleep");
|
||||
}
|
||||
|
||||
// FIXME - implement real crypto for linux
|
||||
CryptoEngine *crypto = new CryptoEngine();
|
||||
|
||||
|
@ -142,19 +142,22 @@ static void waitEnterSleep()
|
||||
|
||||
void doDeepSleep(uint64_t msecToWake)
|
||||
{
|
||||
DEBUG_MSG("Entering deep sleep for %llu seconds\n", msecToWake / 1000);
|
||||
DEBUG_MSG("Entering deep sleep for %lu seconds\n", msecToWake / 1000);
|
||||
|
||||
#ifndef NO_ESP32
|
||||
// not using wifi yet, but once we are this is needed to shutoff the radio hw
|
||||
// esp_wifi_stop();
|
||||
waitEnterSleep();
|
||||
notifySleep.notifyObservers(NULL); // also tell the regular sleep handlers
|
||||
notifyDeepSleep.notifyObservers(NULL);
|
||||
|
||||
screen->setOn(false); // datasheet says this will draw only 10ua
|
||||
screen->doDeepSleep(); // datasheet says this will draw only 10ua
|
||||
|
||||
nodeDB.saveToDisk();
|
||||
|
||||
// Kill GPS power completely (even if previously we just had it in sleep mode)
|
||||
setGPSPower(false);
|
||||
|
||||
setLed(false);
|
||||
|
||||
#ifdef RESET_OLED
|
||||
digitalWrite(RESET_OLED, 1); // put the display in reset before killing its power
|
||||
#endif
|
||||
@ -163,11 +166,6 @@ void doDeepSleep(uint64_t msecToWake)
|
||||
digitalWrite(VEXT_ENABLE, 1); // turn off the display power
|
||||
#endif
|
||||
|
||||
// Kill GPS power completely (even if previously we just had it in sleep mode)
|
||||
setGPSPower(false);
|
||||
|
||||
setLed(false);
|
||||
|
||||
#ifdef TBEAM_V10
|
||||
if (axp192_found) {
|
||||
// Obsolete comment: from back when we we used to receive lora packets while CPU was in deep sleep.
|
||||
@ -185,57 +183,7 @@ void doDeepSleep(uint64_t msecToWake)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
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.
|
||||
|
||||
Note: we don't isolate pins that are used for the LORA, LED, i2c, spi or the wake button
|
||||
*/
|
||||
static const uint8_t rtcGpios[] = {/* 0, */ 2,
|
||||
/* 4, */
|
||||
#ifndef USE_JTAG
|
||||
13,
|
||||
/* 14, */ /* 15, */
|
||||
#endif
|
||||
/* 25, */ 26, /* 27, */
|
||||
32, 33, 34, 35,
|
||||
36, 37
|
||||
/* 38, 39 */};
|
||||
|
||||
for (int i = 0; i < sizeof(rtcGpios); i++)
|
||||
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
|
||||
|
||||
// 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.
|
||||
|
||||
// We want RTC peripherals to stay on
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
#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.
|
||||
uint64_t gpioMask = (1ULL << BUTTON_PIN);
|
||||
|
||||
#ifdef BUTTON_NEED_PULLUP
|
||||
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);
|
||||
|
||||
esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ALL_LOW);
|
||||
#endif
|
||||
|
||||
esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
|
||||
esp_deep_sleep_start(); // TBD mA sleep current (battery)
|
||||
#endif
|
||||
cpuDeepSleep(msecToWake);
|
||||
}
|
||||
|
||||
#ifndef NO_ESP32
|
||||
|
@ -4,7 +4,8 @@
|
||||
#include "Observer.h"
|
||||
#include "configuration.h"
|
||||
|
||||
void doDeepSleep(uint64_t msecToWake);
|
||||
void doDeepSleep(uint64_t msecToWake), cpuDeepSleep(uint64_t msecToWake);
|
||||
|
||||
#ifndef NO_ESP32
|
||||
#include "esp_sleep.h"
|
||||
esp_sleep_wakeup_cause_t doLightSleep(uint64_t msecToWake);
|
||||
|
@ -205,6 +205,7 @@ External serial flash WP25R1635FZUIL0
|
||||
#define PIN_EINK_MOSI (0 + 29) // also called SDI
|
||||
|
||||
// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
|
||||
// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
|
||||
#define PIN_EINK_PWR_ON (0 + 12)
|
||||
|
||||
#define HAS_EINK
|
||||
|
@ -147,7 +147,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
|
||||
#define SX1262_ANT_SW (32 + 10) // P1.10
|
||||
|
||||
// To debug via the segger JLINK console rather than the CDC-ACM serial device
|
||||
#define USE_SEGGER
|
||||
// #define USE_SEGGER
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
|
||||
#define LORA_DISABLE_SENDING // Define this to disable transmission for testing (power testing etc...)
|
||||
|
||||
// To debug via the segger JLINK console rather than the CDC-ACM serial device
|
||||
#define USE_SEGGER
|
||||
// #define USE_SEGGER
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user