Compare commits

...

18 Commits
0.1.5 ... 0.1.6

Author SHA1 Message Date
geeksville
0d62a2be85 release 0.1.6 2020-03-14 18:48:15 -07:00
geeksville
9c971d3686 Finally - new sexy ultra low power/low latency GPS code is in for TBEAM 2020-03-14 18:45:24 -07:00
geeksville
3c1357b732 ublox is better but still not perfect 2020-03-14 16:31:12 -07:00
geeksville
acd5e5d29d use power save mode on gps 2020-03-14 13:33:53 -07:00
geeksville
64109b25f2 Switch to native ublox api for GPS position and time 2020-03-14 12:46:24 -07:00
geeksville
e93bc76ac9 Merge branch 'master' into gps-sleep-mode 2020-03-13 22:45:40 -07:00
geeksville
1107c6d23d Fix serious bug: button presses were not waking from light-sleep on TBEAM
Root cause seems to be the axp192 interrupt, which on some boards fires
during sleep.  I'm not sure why, but we don't need this yet, so leaving
masked during sleep.
2020-03-13 22:42:43 -07:00
geeksville
9b2155402d todo update 2020-03-13 22:41:12 -07:00
geeksville
35cf8a4859 power debugging 2020-03-13 22:38:58 -07:00
geeksville
76f21dfd6e wip 2020-03-13 22:34:44 -07:00
geeksville
b101dc2c88 wip 2020-03-13 20:48:37 -07:00
geeksville
9bbd658b9d begin testing native ublox api 2020-03-13 20:30:48 -07:00
geeksville
4999da0824 Merge branch 'dev' into gps-sleep-mode
# Conflicts:
#	docs/software/TODO.md
#	platformio.ini
2020-03-13 18:48:38 -07:00
geeksville
a783341df1 begin adding temporary support for both NEMA and UBLOX gpses 2020-03-13 18:44:14 -07:00
geeksville
04258755e7 change from gitter to discourse. 2020-03-13 15:06:51 -07:00
geeksville
ea711ece1f new firmware released 2020-03-13 15:03:47 -07:00
geeksville
635e189007 GPS sleep mode WIP - alas this thread will have to be back burner for a
while because my TX wire on my ONLY T-BEAM broke while I was soldering
a jtag connector - so I can only RX from the GPS.

My other 5 boards are still delayed due to corona virus.

So I'll work on other features for now
2020-02-22 20:05:38 -08:00
geeksville
6eba792537 WIP - changing to a ublox aware GPS lib so I can put it in sleep 2020-02-22 19:08:16 -08:00
15 changed files with 164 additions and 69 deletions

View File

@@ -13,7 +13,7 @@ will optionally work with your phone, but no phone is required.
Typical time between recharging the radios should be about eight days.
This project is currently early-alpha, but if you have questions please join our chat [![Join the chat at https://gitter.im/Meshtastic/community](https://badges.gitter.im/Meshtastic/community.svg)](https://gitter.im/Meshtastic/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge).
This project is currently early-alpha, but if you have questions please [join our discussion forum](https://meshtastic.discourse.group/).
This software is 100% open source and developed by a group of hobbyist experimenters. No warranty is provided, if you'd like to improve it - we'd love your help. Please post in the chat.
@@ -87,7 +87,7 @@ After our rate of change slows a bit, we will make beta builds available here (w
# Development
We'd love to have you join us on this merry little project. Please see our [development documents](./docs/software/sw-design.md) and join us on the gitter chat above.
We'd love to have you join us on this merry little project. Please see our [development documents](./docs/software/sw-design.md) and [join us in our discussion forum](https://meshtastic.discourse.group/).
# Credits

View File

@@ -1,3 +1,3 @@
export VERSION=0.1.5
export VERSION=0.1.6

View File

@@ -30,9 +30,9 @@ Not all of these features are fully implemented yet - see **important** disclaim
* Eventually (within a couple of months) we should have a modified version of Signal that works with this project.
* Very easy sharing of private secured channels. Just share a special link or QR code with friends and they can join your encrypted mesh
This project is currently in early alpha - if you have questions please join our chat [![Join the chat at https://gitter.im/Meshtastic/community](https://badges.gitter.im/Meshtastic/community.svg)](https://gitter.im/Meshtastic/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge).
This project is currently in early alpha - if you have questions please [join our discussion forum](https://meshtastic.discourse.group/).
This software is 100% open source and developed by a group of hobbyist experimenters. No warranty is provided, if you'd like to improve it - we'd love your help. Please post in the [chat](https://gitter.im/Meshtastic/community).
This software is 100% open source and developed by a group of hobbyist experimenters. No warranty is provided, if you'd like to improve it - we'd love your help. Please post in the [forum](https://meshtastic.discourse.group/).
# Updates
@@ -52,7 +52,7 @@ But if you want the bleeding edge app now, we'd love to have your help testing.
1. Join [this Google group](https://groups.google.com/forum/#!forum/meshtastic-alpha-testers) with the account you use in Google Play.
2. Go to this [URL](https://play.google.com/apps/testing/com.geeksville.mesh) to opt-in to the alpha test.
3. If you encounter any problems or have questions, post in our gitter chat and we'll help.
3. If you encounter any problems or have questions, post in our [forum](https://meshtastic.discourse.group/) and we'll help.
If you'd like to help with development, the source code is [on github](https://github.com/meshtastic/Meshtastic-Android).

View File

@@ -15,7 +15,7 @@ For more details see the [device software TODO](https://github.com/meshtastic/Me
# FAQ
If you have a question missing from this faq, please ask on our gitter chat. And if you are feeling extra generous send in a pull-request for this faq.md with whatever we answered ;-).
If you have a question missing from this faq, please [ask in our discussion forum](https://meshtastic.discourse.group/). And if you are feeling extra generous send in a pull-request for this faq.md with whatever we answered ;-).
## Q: Which of the various supported radios should I buy?

View File

@@ -7,6 +7,7 @@ being I have it set at 2 minutes to ensure enough time for a GPS lock from scrat
* use gps sleep mode instead of killing its power (to allow fast position when we wake)
* enable fast lock and low power inside the gps chip
* remeasure wake time power draws now that we run CPU down at 80MHz
* add a SF12 transmit option for _super_ long range
@@ -37,6 +38,7 @@ Items to complete before the first beta release.
During the beta timeframe the following improvements 'would be nice' (and yeah - I guess some of these items count as features, but it is a hobby project ;-) )
* figure out why this fixme is needed: "FIXME, disable wake due to PMU because it seems to fire all the time?"
* If the phone doesn't read fromradio mailbox within X seconds, assume the phone is gone and we can stop queing location msgs
for it (because it will redownload the nodedb when it comes back)
* Figure out why the RF95 ISR is never seeing RH_RF95_VALID_HEADER, so it is not protecting our rx packets from getting stomped on by sends
@@ -195,3 +197,7 @@ until the phone pulls those packets. Ever so often power on bluetooth just so w
* link to the kanban page
* add a getting started page
* finish mesh alg reeval
* ublox gps parsing seems a little buggy (we shouldn't be sending out read solution commands, the device is already broadcasting them)
* turn on gps https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/blob/master/examples/Example18_PowerSaveMode/Example18_PowerSaveMode.ino
* switch gps to 38400 baud https://github.com/sparkfun/SparkFun_Ublox_Arduino_Library/blob/master/examples/Example11_ResetModule/Example2_FactoryDefaultsviaSerial/Example2_FactoryDefaultsviaSerial.ino
* Use Neo-M8M API to put it in sleep mode

View File

@@ -59,14 +59,14 @@ debug_init_break = tbreak setup
; names.
lib_deps =
https://github.com/meshtastic/RadioHead.git
1655 ; TinyGPSPlus
https://github.com/meshtastic/esp8266-oled-ssd1306.git ; ESP8266_SSD1306
AXP202X_Library
SPI
1260 ; OneButton
; 1260 ; OneButton - not used yet
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
Wire ; explicitly needed here because the AXP202 library forgets to add it
https://github.com/meshtastic/arduino-fsm.git
https://github.com/geeksville/arduino-fsm.git
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
;[env:tbeam]
;board = ttgo-t-beam

View File

@@ -5,5 +5,5 @@ release. It is used by the android app for forcing software updates. Do not ed
Generated by bin/buildall.sh -->
<resources>
<string name="cur_firmware_version">0.1.3</string>
<string name="cur_firmware_version">0.1.6</string>
</resources>

View File

@@ -21,6 +21,7 @@ CustomRF95::CustomRF95(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &
bool CustomRF95::canSleep()
{
// We allow initializing mode, because sometimes while testing we don't ever call init() to turn on the hardware
DEBUG_MSG("canSleep, mode=%d, isRx=%d, txEmpty=%d, txGood=%d\n", _mode, _isReceiving, txQueue.isEmpty(), _txGood);
return (_mode == RHModeInitialising || _mode == RHModeIdle || _mode == RHModeRx) && !_isReceiving && txQueue.isEmpty();
}

View File

@@ -4,16 +4,18 @@
#include <sys/time.h>
#include "configuration.h"
// stuff that really should be in in the instance instead...
HardwareSerial _serial_gps(GPS_SERIAL_NUM);
uint32_t timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time
uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock
RTC_DATA_ATTR bool timeSetFromGPS; // We only reset our time once per _boot_ after that point just run from the internal clock (even across sleeps)
GPS gps;
bool hasValidLocation; // default to false, until we complete our first read
bool wantNewLocation = true;
// stuff that really should be in in the instance instead...
static uint32_t timeStartMsec; // Once we have a GPS lock, this is where we hold the initial msec clock that corresponds to that time
static uint64_t zeroOffsetSecs; // GPS based time in secs since 1970 - only updated once on initial lock
static bool hasValidLocation; // default to false, until we complete our first read
static bool wantNewLocation = true;
GPS::GPS() : PeriodicTask()
{
@@ -21,10 +23,64 @@ GPS::GPS() : PeriodicTask()
void GPS::setup()
{
readFromRTC();
readFromRTC(); // read the main CPU RTC at first
#ifdef GPS_RX_PIN
_serial_gps.begin(GPS_BAUDRATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);
// _serial_gps.setRxBufferSize(1024); // the default is 256
// ublox.enableDebugging(Serial);
// note: the lib's implementation has the wrong docs for what the return val is
// it is not a bool, it returns zero for success
isConnected = ublox.begin(_serial_gps);
// try a second time, the ublox lib serial parsing is buggy?
// if(!isConnected) isConnected = ublox.begin(_serial_gps);
if (isConnected)
{
DEBUG_MSG("Connected to GPS successfully, TXpin=%d\n", GPS_TX_PIN);
bool factoryReset = false;
bool ok;
if (factoryReset)
{
// It is useful to force back into factory defaults (9600baud, NEMA to test the behavior of boards that don't have GPS_TX connected)
ublox.factoryReset();
delay(2000);
isConnected = ublox.begin(_serial_gps);
DEBUG_MSG("Factory reset success=%d\n", isConnected);
if (isConnected)
{
ublox.assumeAutoPVT(true, true); // Just parse NEMA for now
}
}
else
{
ok = ublox.setUART1Output(COM_TYPE_UBX, 500); // Use native API
assert(ok);
ok = ublox.setNavigationFrequency(1, 500); //Produce 4x/sec to keep the amount of time we stall in getPVT low
assert(ok);
//ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M
//assert(ok);
//ok = ublox.setDynamicModel(DYN_MODEL_BIKE); // probably PEDESTRIAN but just in case assume bike speeds
//assert(ok);
ok = ublox.powerSaveMode(); //use power save mode
assert(ok);
}
ok = ublox.saveConfiguration(2000);
assert(ok);
}
else
{
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
// assume NEMA at 9600 baud.
DEBUG_MSG("ERROR: No bidirectional GPS found, hoping that it still might work\n");
// tell lib, we are expecting the module to send PVT messages by itself to our Rx pin
// you can set second parameter to "false" if you want to control the parsing and eviction of the data (need to call checkUblox cyclically)
ublox.assumeAutoPVT(true, true);
}
#endif
}
@@ -75,20 +131,13 @@ uint32_t GPS::getValidTime()
/// Returns true if we think the board can enter deep or light sleep now (we might be trying to get a GPS lock)
bool GPS::canSleep()
{
return !wantNewLocation;
return true; // we leave GPS on during sleep now, so sleep is okay !wantNewLocation;
}
/// Prepare the GPS for the cpu entering deep or light sleep, expect to be gone for at least 100s of msecs
void GPS::prepareSleep()
{
// discard all rx serial bytes so we don't try to parse them when we come back
while (_serial_gps.available())
{
_serial_gps.read();
}
// make the parser bail on whatever it was parsing
encode('\n');
ublox.powerOff();
}
void GPS::doTask()
@@ -96,49 +145,68 @@ void GPS::doTask()
#ifdef GPS_RX_PIN
// Consume all characters that have arrived
while (_serial_gps.available())
{
encode(_serial_gps.read());
// DEBUG_MSG("Got GPS response\n");
}
// getPVT automatically calls checkUblox
ublox.checkUblox(); //See if new data is available. Process bytes as they come in.
if (!timeSetFromGPS && time.isValid() && date.isValid())
// DEBUG_MSG("sec %d\n", ublox.getSecond());
// DEBUG_MSG("lat %d\n", ublox.getLatitude());
// If we don't have a fix (a quick check), don't try waiting for a solution)
uint8_t fixtype = ublox.getFixType();
DEBUG_MSG("fix type %d\n", fixtype);
// any fix that has time
if ((fixtype >= 2 && fixtype <= 5) && !timeSetFromGPS && ublox.getT())
{
struct timeval tv;
DEBUG_MSG("Got time from GPS\n");
isConnected = true; // We just received a packet, so we must have a GPS
/* Convert to unix time
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
*/
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January 1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
*/
struct tm t;
t.tm_sec = time.second();
t.tm_min = time.minute();
t.tm_hour = time.hour();
t.tm_mday = date.day();
t.tm_mon = date.month() - 1;
t.tm_year = date.year() - 1900;
t.tm_sec = ublox.getSecond();
t.tm_min = ublox.getMinute();
t.tm_hour = ublox.getHour();
t.tm_mday = ublox.getDay();
t.tm_mon = ublox.getMonth() - 1;
t.tm_year = ublox.getYear() - 1900;
t.tm_isdst = false;
time_t res = mktime(&t);
tv.tv_sec = res;
tv.tv_usec = 0; // time.centisecond() * (10 / 1000);
DEBUG_MSG("Got time from GPS month=%d, year=%d, unixtime=%ld\n", t.tm_mon, t.tm_year, tv.tv_sec);
perhapsSetRTC(&tv);
}
#endif
if (location.isValid() && location.isUpdated())
{ // we only notify if position has changed
// DEBUG_MSG("new gps pos\n");
hasValidLocation = true;
wantNewLocation = false;
notifyObservers();
if ((fixtype >= 3 && fixtype <= 4) && ublox.getP()) // rd fixes only
{
// we only notify if position has changed
isConnected = true; // We just received a packet, so we must have a GPS
latitude = ublox.getLatitude() * 1e-7;
longitude = ublox.getLongitude() * 1e-7;
altitude = ublox.getAltitude() / 1000; // in mm convert to meters
DEBUG_MSG("new gps pos lat=%f, lon=%f, alt=%d\n", latitude, longitude, altitude);
hasValidLocation = (latitude != 0) || (longitude != 0); // bogus lat lon is reported as 0,0
if (hasValidLocation)
{
wantNewLocation = false;
notifyObservers();
//ublox.powerOff();
}
}
else // we didn't get a location update, go back to sleep and hope the characters show up
wantNewLocation = true;
// Once we have sent a location once we only poll the GPS rarely, otherwise check back every 100ms until we have something over the serial
setPeriod(hasValidLocation && !wantNewLocation ? 30 * 1000 : 100);
#endif
// Once we have sent a location once we only poll the GPS rarely, otherwise check back every 1s until we have something over the serial
setPeriod(hasValidLocation && !wantNewLocation ? 30 * 1000 : 10 * 1000);
}
void GPS::startLock()
@@ -147,11 +215,3 @@ void GPS::startLock()
wantNewLocation = true;
setPeriod(1);
}
String GPS::getTimeStr()
{
static char t[12]; // used to sprintf for Serial output
snprintf(t, sizeof(t), "%02d:%02d:%02d", time.hour(), time.minute(), time.second());
return t;
}

View File

@@ -1,18 +1,24 @@
#pragma once
#include <TinyGPS++.h>
#include "PeriodicTask.h"
#include "Observer.h"
#include "sys/time.h"
#include "SparkFun_Ublox_Arduino_Library.h"
/**
* A gps class that only reads from the GPS periodically (and FIXME - eventually keeps the gps powered down except when reading)
*
* When new data is available it will notify observers.
*/
class GPS : public PeriodicTask, public Observable, public TinyGPSPlus
class GPS : public PeriodicTask, public Observable
{
SFE_UBLOX_GPS ublox;
public:
double latitude, longitude;
uint32_t altitude;
bool isConnected; // Do we have a GPS we are talking to
GPS();
/// Return time since 1970 in secs. Until we have a GPS lock we will be returning time based at zero
@@ -21,8 +27,6 @@ public:
/// Return time since 1970 in secs. If we don't have a GPS lock return zero
uint32_t getValidTime();
String getTimeStr();
void setup();
virtual void loop();
@@ -46,3 +50,4 @@ private:
};
extern GPS gps;

View File

@@ -326,11 +326,13 @@ void MeshService::onGPSChanged()
MeshPacket *p = allocForSending();
p->payload.which_variant = SubPacket_position_tag;
Position &pos = p->payload.variant.position;
#if 0
if (gps.altitude.isValid())
pos.altitude = gps.altitude.meters();
pos.latitude = gps.location.lat();
pos.longitude = gps.location.lng();
pos.time = gps.getValidTime();
#endif
// We limit our GPS broadcasts to a max rate
static uint32_t lastGpsSend;

View File

@@ -25,6 +25,7 @@ static void sdsEnter()
static void lsEnter()
{
DEBUG_MSG("lsEnter begin\n");
screen.setOn(false);
while (!service.radio.rf95.canSleep())
@@ -32,12 +33,16 @@ static void lsEnter()
gps.prepareSleep(); // abandon in-process parsing
if (!isUSBPowered) // FIXME - temp hack until we can put gps in sleep mode, if we have AC when we go to sleep then leave GPS on
setGPSPower(false); // kill GPS power
//if (!isUSBPowered) // FIXME - temp hack until we can put gps in sleep mode, if we have AC when we go to sleep then leave GPS on
// setGPSPower(false); // kill GPS power
DEBUG_MSG("lsEnter end\n");
}
static void lsIdle()
{
DEBUG_MSG("lsIdle begin ls_secs=%u\n", radioConfig.preferences.ls_secs);
uint32_t secsSlept = 0;
esp_sleep_source_t wakeCause = ESP_SLEEP_WAKEUP_UNDEFINED;
bool reached_ls_secs = false;
@@ -69,6 +74,8 @@ static void lsIdle()
}
else
{
DEBUG_MSG("wakeCause %d\n", wakeCause);
// Regardless of why we woke just transition to NB (and that state will handle stuff like IRQs etc)
powerFSM.trigger(EVENT_WAKE_TIMER);
}
@@ -76,7 +83,7 @@ static void lsIdle()
static void lsExit()
{
setGPSPower(true); // restore GPS power
// setGPSPower(true); // restore GPS power
gps.startLock();
}

View File

@@ -41,8 +41,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Select which board is being used. If the outside build environment has sent a choice, just use that
#if !defined(T_BEAM_V10) && !defined(HELTEC_LORA32)
// #define T_BEAM_V10 // AKA Rev1 (second board released)
#define HELTEC_LORA32
#define T_BEAM_V10 // AKA Rev1 (second board released)
// #define HELTEC_LORA32
#define HW_VERSION_US // We encode the hardware freq range in the hw version string, so sw update can eventually install the correct build
#endif
@@ -108,6 +108,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BICOLOR_DISPLAY // we have yellow at the top 16 lines
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
#define I2C_SDA 21
#define I2C_SCL 22

View File

@@ -341,6 +341,9 @@ void loop()
// axpDebugOutput.loop();
loopBLE();
// for debug printing
// service.radio.rf95.canSleep();
#ifdef T_BEAM_V10
if (axp192_found)
{

View File

@@ -177,6 +177,10 @@ void doDeepSleep(uint64_t msecToWake)
// 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);
@@ -206,15 +210,20 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
// We want RTC peripherals to stay on
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
#ifdef BUTTON_NEED_PULLUP
gpio_pullup_en((gpio_num_t) BUTTON_PIN);
#endif
gpio_wakeup_enable((gpio_num_t)BUTTON_PIN, GPIO_INTR_LOW_LEVEL); // when user presses, this button goes low
gpio_wakeup_enable((gpio_num_t)DIO0_GPIO, GPIO_INTR_HIGH_LEVEL); // RF95 interrupt, active high
#ifdef PMU_IRQ
gpio_wakeup_enable((gpio_num_t)PMU_IRQ, GPIO_INTR_HIGH_LEVEL); // pmu irq
// FIXME, disable wake due to PMU because it seems to fire all the time?
// gpio_wakeup_enable((gpio_num_t)PMU_IRQ, GPIO_INTR_HIGH_LEVEL); // pmu irq
#endif
assert(esp_sleep_enable_gpio_wakeup() == ESP_OK);
assert(esp_sleep_enable_timer_wakeup(sleepUsec) == ESP_OK);
assert(esp_light_sleep_start() == ESP_OK);
//DEBUG_MSG("Exit light sleep\n");
//DEBUG_MSG("Exit light sleep b=%d, rf95=%d, pmu=%d\n", digitalRead(BUTTON_PIN), digitalRead(DIO0_GPIO), digitalRead(PMU_IRQ));
return esp_sleep_get_wakeup_cause();
}