mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-18 08:12:57 +00:00
Merge pull request #46 from geeksville/master
a quick window to sneak in and fix formatting
This commit is contained in:
commit
992b525588
@ -1,20 +1,16 @@
|
|||||||
#include "CustomRF95.h"
|
#include "CustomRF95.h"
|
||||||
#include <pb_encode.h>
|
|
||||||
#include <pb_decode.h>
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "assert.h"
|
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
|
#include "assert.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include <pb_decode.h>
|
||||||
|
#include <pb_encode.h>
|
||||||
|
|
||||||
/// A temporary buffer used for sending/receving packets, sized to hold the biggest buffer we might need
|
/// A temporary buffer used for sending/receving packets, sized to hold the biggest buffer we might need
|
||||||
#define MAX_RHPACKETLEN 251
|
#define MAX_RHPACKETLEN 251
|
||||||
static uint8_t radiobuf[MAX_RHPACKETLEN];
|
static uint8_t radiobuf[MAX_RHPACKETLEN];
|
||||||
|
|
||||||
CustomRF95::CustomRF95(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest)
|
CustomRF95::CustomRF95(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest)
|
||||||
: RH_RF95(NSS_GPIO, DIO0_GPIO),
|
: RH_RF95(NSS_GPIO, DIO0_GPIO), pool(_pool), rxDest(_rxDest), txQueue(MAX_TX_QUEUE), sendingPacket(NULL)
|
||||||
pool(_pool),
|
|
||||||
rxDest(_rxDest),
|
|
||||||
txQueue(MAX_TX_QUEUE),
|
|
||||||
sendingPacket(NULL)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,15 +45,12 @@ ErrorCode CustomRF95::send(MeshPacket *p)
|
|||||||
// We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one).
|
// 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,
|
// 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.
|
// we almost certainly guarantee no one outside will like the packet we are sending.
|
||||||
if (_mode == RHModeIdle || (_mode == RHModeRx && !_isReceiving))
|
if (_mode == RHModeIdle || (_mode == RHModeRx && !_isReceiving)) {
|
||||||
{
|
|
||||||
// if the radio is idle, we can send right away
|
// if the radio is idle, we can send right away
|
||||||
DEBUG_MSG("immedate send on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", txGood(), rxGood(), rxBad());
|
DEBUG_MSG("immedate send on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", txGood(), rxGood(), rxBad());
|
||||||
startSend(p);
|
startSend(p);
|
||||||
return ERRNO_OK;
|
return ERRNO_OK;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_MSG("enquing packet for send from=0x%x, to=0x%x\n", p->from, p->to);
|
DEBUG_MSG("enquing packet for send from=0x%x, to=0x%x\n", p->from, p->to);
|
||||||
ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
|
ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||||
|
|
||||||
@ -68,7 +61,8 @@ ErrorCode CustomRF95::send(MeshPacket *p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// After doing standard behavior, check to see if a new packet arrived or one was sent and start a new send or receive as necessary
|
// After doing standard behavior, check to see if a new packet arrived or one was sent and start a new send or receive as
|
||||||
|
// necessary
|
||||||
void CustomRF95::handleInterrupt()
|
void CustomRF95::handleInterrupt()
|
||||||
{
|
{
|
||||||
RH_RF95::handleInterrupt();
|
RH_RF95::handleInterrupt();
|
||||||
@ -85,8 +79,7 @@ void CustomRF95::handleInterrupt()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we just finished receiving a packet, forward it into a queue
|
// If we just finished receiving a packet, forward it into a queue
|
||||||
if (_rxBufValid)
|
if (_rxBufValid) {
|
||||||
{
|
|
||||||
// We received a packet
|
// We received a packet
|
||||||
|
|
||||||
// Skip the 4 headers that are at the beginning of the rxBuf
|
// Skip the 4 headers that are at the beginning of the rxBuf
|
||||||
@ -111,18 +104,14 @@ void CustomRF95::handleInterrupt()
|
|||||||
// Note: we can't create it at this point, because it might be a bogus User node allocation. But odds are we will
|
// Note: we can't create it at this point, because it might be a bogus User node allocation. But odds are we will
|
||||||
// already have a record we can hide this debugging info in.
|
// already have a record we can hide this debugging info in.
|
||||||
NodeInfo *info = nodeDB.getNode(mp->from);
|
NodeInfo *info = nodeDB.getNode(mp->from);
|
||||||
if (info)
|
if (info) {
|
||||||
{
|
|
||||||
info->snr = snr;
|
info->snr = snr;
|
||||||
info->frequency_error = freqerr;
|
info->frequency_error = freqerr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pb_decode_from_bytes(payload, payloadLen, SubPacket_fields, p))
|
if (!pb_decode_from_bytes(payload, payloadLen, SubPacket_fields, p)) {
|
||||||
{
|
|
||||||
pool.releaseFromISR(mp, &higherPriWoken);
|
pool.releaseFromISR(mp, &higherPriWoken);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// parsing was successful, queue for our recipient
|
// parsing was successful, queue for our recipient
|
||||||
mp->has_payload = true;
|
mp->has_payload = true;
|
||||||
|
|
||||||
@ -152,8 +141,7 @@ bool CustomRF95::handleIdleISR()
|
|||||||
MeshPacket *txp = txQueue.dequeuePtrFromISR(0);
|
MeshPacket *txp = txQueue.dequeuePtrFromISR(0);
|
||||||
if (txp)
|
if (txp)
|
||||||
startSend(txp);
|
startSend(txp);
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
// Nothing to send, let's switch back to receive mode
|
// Nothing to send, let's switch back to receive mode
|
||||||
setModeRx();
|
setModeRx();
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <RH_RF95.h>
|
|
||||||
#include <RHMesh.h>
|
|
||||||
#include "MemoryPool.h"
|
#include "MemoryPool.h"
|
||||||
#include "mesh.pb.h"
|
|
||||||
#include "PointerQueue.h"
|
|
||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
|
#include "PointerQueue.h"
|
||||||
|
#include "mesh.pb.h"
|
||||||
|
#include <RHMesh.h>
|
||||||
|
#include <RH_RF95.h>
|
||||||
|
|
||||||
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
|
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A version of the RF95 driver which is smart enough to manage packets via queues (no polling or blocking in user threads!)
|
* A version of the RF95 driver which is smart enough to manage packets via queues (no polling or blocking in user threads!)
|
||||||
*/
|
*/
|
||||||
@ -46,7 +45,8 @@ public:
|
|||||||
bool init();
|
bool init();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// After doing standard behavior, check to see if a new packet arrived or one was sent and start a new send or receive as necessary
|
// After doing standard behavior, check to see if a new packet arrived or one was sent and start a new send or receive as
|
||||||
|
// necessary
|
||||||
virtual void handleInterrupt();
|
virtual void handleInterrupt();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -35,7 +35,8 @@ void GPS::setup()
|
|||||||
isConnected = ublox.begin(_serial_gps);
|
isConnected = ublox.begin(_serial_gps);
|
||||||
|
|
||||||
// try a second time, the ublox lib serial parsing is buggy?
|
// try a second time, the ublox lib serial parsing is buggy?
|
||||||
if(!isConnected) isConnected = ublox.begin(_serial_gps);
|
if (!isConnected)
|
||||||
|
isConnected = ublox.begin(_serial_gps);
|
||||||
|
|
||||||
if (isConnected) {
|
if (isConnected) {
|
||||||
DEBUG_MSG("Connected to GPS successfully, TXpin=%d\n", GPS_TX_PIN);
|
DEBUG_MSG("Connected to GPS successfully, TXpin=%d\n", GPS_TX_PIN);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "PeriodicTask.h"
|
|
||||||
#include "Observer.h"
|
#include "Observer.h"
|
||||||
#include "sys/time.h"
|
#include "PeriodicTask.h"
|
||||||
#include "SparkFun_Ublox_Arduino_Library.h"
|
#include "SparkFun_Ublox_Arduino_Library.h"
|
||||||
|
#include "sys/time.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A gps class that only reads from the GPS periodically (and FIXME - eventually keeps the gps powered down except when reading)
|
* A gps class that only reads from the GPS periodically (and FIXME - eventually keeps the gps powered down except when reading)
|
||||||
@ -50,4 +50,3 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern GPS gps;
|
extern GPS gps;
|
||||||
|
|
||||||
|
@ -10,8 +10,7 @@
|
|||||||
*
|
*
|
||||||
* Eventually this routine will even be safe for ISR use...
|
* Eventually this routine will even be safe for ISR use...
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T> class MemoryPool
|
||||||
class MemoryPool
|
|
||||||
{
|
{
|
||||||
PointerQueue<T> dead;
|
PointerQueue<T> dead;
|
||||||
|
|
||||||
@ -29,10 +28,7 @@ public:
|
|||||||
release(&buf[i]);
|
release(&buf[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
~MemoryPool()
|
~MemoryPool() { delete[] buf; }
|
||||||
{
|
|
||||||
delete[] buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a queable object which has been prefilled with zeros. Panic if no buffer is available
|
/// Return a queable object which has been prefilled with zeros. Panic if no buffer is available
|
||||||
T *allocZeroed()
|
T *allocZeroed()
|
||||||
@ -43,7 +39,8 @@ public:
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you probably don't want this version)
|
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you probably
|
||||||
|
/// don't want this version)
|
||||||
T *allocZeroed(TickType_t maxWait)
|
T *allocZeroed(TickType_t maxWait)
|
||||||
{
|
{
|
||||||
T *p = dead.dequeuePtr(maxWait);
|
T *p = dead.dequeuePtr(maxWait);
|
||||||
@ -67,13 +64,17 @@ public:
|
|||||||
void release(T *p)
|
void release(T *p)
|
||||||
{
|
{
|
||||||
assert(dead.enqueue(p, 0));
|
assert(dead.enqueue(p, 0));
|
||||||
assert(p >= buf && (p - buf) < maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
assert(p >= buf &&
|
||||||
|
(p - buf) <
|
||||||
|
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a buffer from an ISR, if higherPriWoken is set to true you have some work to do ;-)
|
/// Return a buffer from an ISR, if higherPriWoken is set to true you have some work to do ;-)
|
||||||
void releaseFromISR(T *p, BaseType_t *higherPriWoken)
|
void releaseFromISR(T *p, BaseType_t *higherPriWoken)
|
||||||
{
|
{
|
||||||
assert(dead.enqueueFromISR(p, higherPriWoken));
|
assert(dead.enqueueFromISR(p, higherPriWoken));
|
||||||
assert(p >= buf && (p - buf) < maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
assert(p >= buf &&
|
||||||
|
(p - buf) <
|
||||||
|
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
#include "BluetoothUtil.h"
|
|
||||||
#include "MeshBluetoothService.h"
|
#include "MeshBluetoothService.h"
|
||||||
#include <esp_gatt_defs.h>
|
#include "BluetoothUtil.h"
|
||||||
#include <BLE2902.h>
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <BLE2902.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <esp_gatt_defs.h>
|
||||||
|
|
||||||
#include "mesh.pb.h"
|
|
||||||
#include "MeshService.h"
|
|
||||||
#include "mesh-pb-constants.h"
|
|
||||||
#include "NodeDB.h"
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "PowerFSM.h"
|
|
||||||
#include "CallbackCharacteristic.h"
|
#include "CallbackCharacteristic.h"
|
||||||
|
#include "MeshService.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
|
#include "PowerFSM.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "mesh-pb-constants.h"
|
||||||
|
#include "mesh.pb.h"
|
||||||
|
|
||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
|
|
||||||
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in proccess at once
|
// This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in
|
||||||
|
// proccess at once
|
||||||
static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)];
|
static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)];
|
||||||
|
|
||||||
class ProtobufCharacteristic : public CallbackCharacteristic
|
class ProtobufCharacteristic : public CallbackCharacteristic
|
||||||
@ -25,9 +26,7 @@ class ProtobufCharacteristic : public CallbackCharacteristic
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
ProtobufCharacteristic(const char *uuid, uint32_t btprops, const pb_msgdesc_t *_fields, void *_my_struct)
|
ProtobufCharacteristic(const char *uuid, uint32_t btprops, const pb_msgdesc_t *_fields, void *_my_struct)
|
||||||
: CallbackCharacteristic(uuid, btprops),
|
: CallbackCharacteristic(uuid, btprops), fields(_fields), my_struct(_my_struct)
|
||||||
fields(_fields),
|
|
||||||
my_struct(_my_struct)
|
|
||||||
{
|
{
|
||||||
setCallbacks(this);
|
setCallbacks(this);
|
||||||
}
|
}
|
||||||
@ -63,7 +62,8 @@ class NodeInfoCharacteristic : public BLECharacteristic, public BLEKeepAliveCall
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NodeInfoCharacteristic()
|
NodeInfoCharacteristic()
|
||||||
: BLECharacteristic("d31e02e0-c8ab-4d3f-9cc9-0b8466bdabe8", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ)
|
: BLECharacteristic("d31e02e0-c8ab-4d3f-9cc9-0b8466bdabe8",
|
||||||
|
BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ)
|
||||||
{
|
{
|
||||||
setCallbacks(this);
|
setCallbacks(this);
|
||||||
}
|
}
|
||||||
@ -74,14 +74,12 @@ public:
|
|||||||
|
|
||||||
const NodeInfo *info = nodeDB.readNextInfo();
|
const NodeInfo *info = nodeDB.readNextInfo();
|
||||||
|
|
||||||
if (info)
|
if (info) {
|
||||||
{
|
DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->position.time, info->user.id,
|
||||||
DEBUG_MSG("Sending nodeinfo: num=0x%x, lastseen=%u, id=%s, name=%s\n", info->num, info->position.time, info->user.id, info->user.long_name);
|
info->user.long_name);
|
||||||
size_t numbytes = pb_encode_to_bytes(trBytes, sizeof(trBytes), NodeInfo_fields, info);
|
size_t numbytes = pb_encode_to_bytes(trBytes, sizeof(trBytes), NodeInfo_fields, info);
|
||||||
c->setValue(trBytes, numbytes);
|
c->setValue(trBytes, numbytes);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
c->setValue(trBytes, 0); // Send an empty response
|
c->setValue(trBytes, 0); // Send an empty response
|
||||||
DEBUG_MSG("Done sending nodeinfos\n");
|
DEBUG_MSG("Done sending nodeinfos\n");
|
||||||
}
|
}
|
||||||
@ -95,13 +93,14 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// wrap our protobuf version with something that forces the service to reload the config
|
// wrap our protobuf version with something that forces the service to reload the config
|
||||||
class RadioCharacteristic : public ProtobufCharacteristic
|
class RadioCharacteristic : public ProtobufCharacteristic
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RadioCharacteristic()
|
RadioCharacteristic()
|
||||||
: ProtobufCharacteristic("b56786c8-839a-44a1-b98e-a1724c4a0262", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ, RadioConfig_fields, &radioConfig)
|
: ProtobufCharacteristic("b56786c8-839a-44a1-b98e-a1724c4a0262",
|
||||||
|
BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ, RadioConfig_fields,
|
||||||
|
&radioConfig)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,31 +126,29 @@ class OwnerCharacteristic : public ProtobufCharacteristic
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OwnerCharacteristic()
|
OwnerCharacteristic()
|
||||||
: ProtobufCharacteristic("6ff1d8b6-e2de-41e3-8c0b-8fa384f64eb6", BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ, User_fields, &owner)
|
: ProtobufCharacteristic("6ff1d8b6-e2de-41e3-8c0b-8fa384f64eb6",
|
||||||
|
BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ, User_fields, &owner)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void onWrite(BLECharacteristic *c)
|
void onWrite(BLECharacteristic *c)
|
||||||
{
|
{
|
||||||
BLEKeepAliveCallbacks::onWrite(c); // NOTE: We do not call the standard ProtobufCharacteristic superclass, because we want custom write behavior
|
BLEKeepAliveCallbacks::onWrite(
|
||||||
|
c); // NOTE: We do not call the standard ProtobufCharacteristic superclass, because we want custom write behavior
|
||||||
|
|
||||||
static User o; // if the phone doesn't set ID we are careful to keep ours, we also always keep our macaddr
|
static User o; // if the phone doesn't set ID we are careful to keep ours, we also always keep our macaddr
|
||||||
if (writeToDest(c, &o))
|
if (writeToDest(c, &o)) {
|
||||||
{
|
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
|
|
||||||
if (*o.long_name)
|
if (*o.long_name) {
|
||||||
{
|
|
||||||
changed |= strcmp(owner.long_name, o.long_name);
|
changed |= strcmp(owner.long_name, o.long_name);
|
||||||
strcpy(owner.long_name, o.long_name);
|
strcpy(owner.long_name, o.long_name);
|
||||||
}
|
}
|
||||||
if (*o.short_name)
|
if (*o.short_name) {
|
||||||
{
|
|
||||||
changed |= strcmp(owner.short_name, o.short_name);
|
changed |= strcmp(owner.short_name, o.short_name);
|
||||||
strcpy(owner.short_name, o.short_name);
|
strcpy(owner.short_name, o.short_name);
|
||||||
}
|
}
|
||||||
if (*o.id)
|
if (*o.id) {
|
||||||
{
|
|
||||||
changed |= strcmp(owner.id, o.id);
|
changed |= strcmp(owner.id, o.id);
|
||||||
strcpy(owner.id, o.id);
|
strcpy(owner.id, o.id);
|
||||||
}
|
}
|
||||||
@ -165,10 +162,7 @@ public:
|
|||||||
class ToRadioCharacteristic : public CallbackCharacteristic
|
class ToRadioCharacteristic : public CallbackCharacteristic
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ToRadioCharacteristic()
|
ToRadioCharacteristic() : CallbackCharacteristic("f75c76d2-129e-4dad-a1dd-7866124401e7", BLECharacteristic::PROPERTY_WRITE) {}
|
||||||
: CallbackCharacteristic("f75c76d2-129e-4dad-a1dd-7866124401e7", BLECharacteristic::PROPERTY_WRITE)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void onWrite(BLECharacteristic *c)
|
void onWrite(BLECharacteristic *c)
|
||||||
{
|
{
|
||||||
@ -182,8 +176,7 @@ public:
|
|||||||
class FromRadioCharacteristic : public CallbackCharacteristic
|
class FromRadioCharacteristic : public CallbackCharacteristic
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FromRadioCharacteristic()
|
FromRadioCharacteristic() : CallbackCharacteristic("8ba2bcc2-ee02-4a55-a531-c525c5e454d5", BLECharacteristic::PROPERTY_READ)
|
||||||
: CallbackCharacteristic("8ba2bcc2-ee02-4a55-a531-c525c5e454d5", BLECharacteristic::PROPERTY_READ)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,13 +187,10 @@ public:
|
|||||||
|
|
||||||
// Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue
|
// 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
|
// or make empty if the queue is empty
|
||||||
if (!mp)
|
if (!mp) {
|
||||||
{
|
|
||||||
DEBUG_MSG("toPhone queue is empty\n");
|
DEBUG_MSG("toPhone queue is empty\n");
|
||||||
c->setValue((uint8_t *)"", 0);
|
c->setValue((uint8_t *)"", 0);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
static FromRadio fRadio;
|
static FromRadio fRadio;
|
||||||
|
|
||||||
// Encapsulate as a FromRadio packet
|
// Encapsulate as a FromRadio packet
|
||||||
@ -221,8 +211,9 @@ class FromNumCharacteristic : public CallbackCharacteristic
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FromNumCharacteristic()
|
FromNumCharacteristic()
|
||||||
: CallbackCharacteristic("ed9da18c-a800-4f66-a670-aa7547e34453",
|
: CallbackCharacteristic("ed9da18c-a800-4f66-a670-aa7547e34453", BLECharacteristic::PROPERTY_WRITE |
|
||||||
BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY)
|
BLECharacteristic::PROPERTY_READ |
|
||||||
|
BLECharacteristic::PROPERTY_NOTIFY)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,8 +231,7 @@ FromNumCharacteristic *meshFromNumCharacteristic;
|
|||||||
*/
|
*/
|
||||||
void bluetoothNotifyFromNum(uint32_t newValue)
|
void bluetoothNotifyFromNum(uint32_t newValue)
|
||||||
{
|
{
|
||||||
if (meshFromNumCharacteristic)
|
if (meshFromNumCharacteristic) {
|
||||||
{
|
|
||||||
// if bt not running ignore
|
// if bt not running ignore
|
||||||
meshFromNumCharacteristic->setValue(newValue);
|
meshFromNumCharacteristic->setValue(newValue);
|
||||||
meshFromNumCharacteristic->notify();
|
meshFromNumCharacteristic->notify();
|
||||||
@ -265,7 +255,10 @@ BLEService *createMeshBluetoothService(BLEServer *server)
|
|||||||
addWithDesc(service, new ToRadioCharacteristic, "toRadio");
|
addWithDesc(service, new ToRadioCharacteristic, "toRadio");
|
||||||
addWithDesc(service, new FromRadioCharacteristic, "fromNum");
|
addWithDesc(service, new FromRadioCharacteristic, "fromNum");
|
||||||
|
|
||||||
addWithDesc(service, new ProtobufCharacteristic("ea9f3f82-8dc4-4733-9452-1f6da28892a2", BLECharacteristic::PROPERTY_READ, MyNodeInfo_fields, &myNodeInfo), "myNode");
|
addWithDesc(service,
|
||||||
|
new ProtobufCharacteristic("ea9f3f82-8dc4-4733-9452-1f6da28892a2", BLECharacteristic::PROPERTY_READ,
|
||||||
|
MyNodeInfo_fields, &myNodeInfo),
|
||||||
|
"myNode");
|
||||||
addWithDesc(service, new RadioCharacteristic, "radio");
|
addWithDesc(service, new RadioCharacteristic, "radio");
|
||||||
addWithDesc(service, new OwnerCharacteristic, "owner");
|
addWithDesc(service, new OwnerCharacteristic, "owner");
|
||||||
addWithDesc(service, new NodeInfoCharacteristic, "nodeinfo");
|
addWithDesc(service, new NodeInfoCharacteristic, "nodeinfo");
|
||||||
@ -276,8 +269,7 @@ BLEService *createMeshBluetoothService(BLEServer *server)
|
|||||||
|
|
||||||
// We only add to advertisting once, because the ESP32 arduino code is dumb and that object never dies
|
// We only add to advertisting once, because the ESP32 arduino code is dumb and that object never dies
|
||||||
static bool firstTime = true;
|
static bool firstTime = true;
|
||||||
if (firstTime)
|
if (firstTime) {
|
||||||
{
|
|
||||||
firstTime = false;
|
firstTime = false;
|
||||||
server->getAdvertising()->addServiceUUID(service->getUUID());
|
server->getAdvertising()->addServiceUUID(service->getUUID());
|
||||||
}
|
}
|
||||||
@ -295,8 +287,6 @@ void stopMeshBluetoothService()
|
|||||||
meshService->stop();
|
meshService->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void destroyMeshBluetoothService()
|
void destroyMeshBluetoothService()
|
||||||
{
|
{
|
||||||
assert(meshService);
|
assert(meshService);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BLEService.h>
|
|
||||||
#include <BLEServer.h>
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <BLEServer.h>
|
||||||
|
#include <BLEService.h>
|
||||||
|
|
||||||
BLEService *createMeshBluetoothService(BLEServer *server);
|
BLEService *createMeshBluetoothService(BLEServer *server);
|
||||||
void destroyMeshBluetoothService();
|
void destroyMeshBluetoothService();
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
#include <SPI.h>
|
|
||||||
#include "RH_RF95.h"
|
#include "RH_RF95.h"
|
||||||
#include <RHMesh.h>
|
#include <RHMesh.h>
|
||||||
|
#include <SPI.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include <pb_encode.h>
|
|
||||||
#include <pb_decode.h>
|
|
||||||
#include "MeshRadio.h"
|
#include "MeshRadio.h"
|
||||||
#include "configuration.h"
|
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include <pb_decode.h>
|
||||||
|
#include <pb_encode.h>
|
||||||
|
|
||||||
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on
|
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on
|
||||||
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf};
|
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
|
||||||
|
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0xbf};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ## LoRaWAN for North America
|
* ## LoRaWAN for North America
|
||||||
@ -19,21 +20,20 @@ LoRaWAN defines 64, 125 kHz channels from 902.3 to 914.9 MHz increments.
|
|||||||
|
|
||||||
The maximum output power for North America is +30 dBM.
|
The maximum output power for North America is +30 dBM.
|
||||||
|
|
||||||
The band is from 902 to 928 MHz. It mentions channel number and its respective channel frequency. All the 13 channels are separated by 2.16 MHz with respect to the adjacent channels.
|
The band is from 902 to 928 MHz. It mentions channel number and its respective channel frequency. All the 13 channels are
|
||||||
Channel zero starts at 903.08 MHz center frequency.
|
separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts at 903.08 MHz center frequency.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// Sometimes while debugging it is useful to set this false, to disable rf95 accesses
|
/// Sometimes while debugging it is useful to set this false, to disable rf95 accesses
|
||||||
bool useHardware = true;
|
bool useHardware = true;
|
||||||
|
|
||||||
MeshRadio::MeshRadio(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest)
|
MeshRadio::MeshRadio(MemoryPool<MeshPacket> &_pool, PointerQueue<MeshPacket> &_rxDest) : rf95(_pool, _rxDest), manager(rf95)
|
||||||
: rf95(_pool, _rxDest),
|
|
||||||
manager(rf95)
|
|
||||||
{
|
{
|
||||||
myNodeInfo.num_channels = NUM_CHANNELS;
|
myNodeInfo.num_channels = NUM_CHANNELS;
|
||||||
|
|
||||||
// radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast
|
// radioConfig.modem_config = RadioConfig_ModemConfig_Bw125Cr45Sf128; // medium range and fast
|
||||||
//channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide bandwidth so incompatible radios can talk together
|
// channelSettings.modem_config = ChannelSettings_ModemConfig_Bw500Cr45Sf128; // short range and fast, but wide bandwidth so
|
||||||
|
// incompatible radios can talk together
|
||||||
channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range
|
channelSettings.modem_config = ChannelSettings_ModemConfig_Bw125Cr48Sf4096; // slow and long range
|
||||||
|
|
||||||
channelSettings.tx_power = 23;
|
channelSettings.tx_power = 23;
|
||||||
@ -61,10 +61,10 @@ bool MeshRadio::init()
|
|||||||
delay(10);
|
delay(10);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
manager.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor time.
|
manager.setThisAddress(
|
||||||
|
nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor time.
|
||||||
|
|
||||||
if (!manager.init())
|
if (!manager.init()) {
|
||||||
{
|
|
||||||
DEBUG_MSG("LoRa radio init failed\n");
|
DEBUG_MSG("LoRa radio init failed\n");
|
||||||
DEBUG_MSG("Uncomment '#define SERIAL_DEBUG' in RH_RF95.cpp for detailed debug info\n");
|
DEBUG_MSG("Uncomment '#define SERIAL_DEBUG' in RH_RF95.cpp for detailed debug info\n");
|
||||||
return false;
|
return false;
|
||||||
@ -100,15 +100,15 @@ void MeshRadio::reloadConfig()
|
|||||||
|
|
||||||
// Set up default configuration
|
// Set up default configuration
|
||||||
// No Sync Words in LORA mode.
|
// No Sync Words in LORA mode.
|
||||||
rf95.setModemConfig((RH_RF95::ModemConfigChoice)channelSettings.modem_config); // Radio default
|
rf95.setModemConfig(
|
||||||
|
(RH_RF95::ModemConfigChoice)channelSettings.modem_config); // Radio default
|
||||||
// setModemConfig(Bw125Cr48Sf4096); // slow and reliable?
|
// setModemConfig(Bw125Cr48Sf4096); // slow and reliable?
|
||||||
// rf95.setPreambleLength(8); // Default is 8
|
// rf95.setPreambleLength(8); // Default is 8
|
||||||
|
|
||||||
// Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
|
// Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
|
||||||
int channel_num = hash(channelSettings.name) % NUM_CHANNELS;
|
int channel_num = hash(channelSettings.name) % NUM_CHANNELS;
|
||||||
float center_freq = CH0 + CH_SPACING * channel_num;
|
float center_freq = CH0 + CH_SPACING * channel_num;
|
||||||
if (!rf95.setFrequency(center_freq))
|
if (!rf95.setFrequency(center_freq)) {
|
||||||
{
|
|
||||||
DEBUG_MSG("setFrequency failed\n");
|
DEBUG_MSG("setFrequency failed\n");
|
||||||
assert(0); // fixme panic
|
assert(0); // fixme panic
|
||||||
}
|
}
|
||||||
@ -121,7 +121,8 @@ void MeshRadio::reloadConfig()
|
|||||||
// FIXME - can we do this? It seems to be in the Heltec board.
|
// FIXME - can we do this? It seems to be in the Heltec board.
|
||||||
rf95.setTxPower(channelSettings.tx_power, false);
|
rf95.setTxPower(channelSettings.tx_power, false);
|
||||||
|
|
||||||
DEBUG_MSG("Set radio: name=%s. config=%u, ch=%d, txpower=%d\n", channelSettings.name, channelSettings.modem_config, channel_num, channelSettings.tx_power);
|
DEBUG_MSG("Set radio: name=%s. config=%u, ch=%d, txpower=%d\n", channelSettings.name, channelSettings.modem_config,
|
||||||
|
channel_num, channelSettings.tx_power);
|
||||||
|
|
||||||
// Done with init tell radio to start receiving
|
// Done with init tell radio to start receiving
|
||||||
rf95.setModeRx();
|
rf95.setModeRx();
|
||||||
@ -131,8 +132,7 @@ ErrorCode MeshRadio::send(MeshPacket *p)
|
|||||||
{
|
{
|
||||||
if (useHardware)
|
if (useHardware)
|
||||||
return rf95.send(p);
|
return rf95.send(p);
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
rf95.pool.release(p);
|
rf95.pool.release(p);
|
||||||
return ERRNO_OK;
|
return ERRNO_OK;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CustomRF95.h"
|
#include "CustomRF95.h"
|
||||||
#include <RHMesh.h>
|
|
||||||
#include "MemoryPool.h"
|
#include "MemoryPool.h"
|
||||||
#include "mesh.pb.h"
|
|
||||||
#include "PointerQueue.h"
|
|
||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
|
#include "PointerQueue.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "mesh.pb.h"
|
||||||
|
#include <RHMesh.h>
|
||||||
|
|
||||||
// US channel settings
|
// US channel settings
|
||||||
#define CH0_US 903.08f // MHz
|
#define CH0_US 903.08f // MHz
|
||||||
@ -58,13 +58,14 @@
|
|||||||
#error "HW_VERSION not set"
|
#error "HW_VERSION not set"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A raw low level interface to our mesh. Only understands nodenums and bytes (not protobufs or node ids)
|
* A raw low level interface to our mesh. Only understands nodenums and bytes (not protobufs or node ids)
|
||||||
*/
|
*/
|
||||||
class MeshRadio {
|
class MeshRadio
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
CustomRF95 rf95; // the raw radio interface - for now I'm leaving public - because this class is shrinking to be almost nothing
|
CustomRF95
|
||||||
|
rf95; // the raw radio interface - for now I'm leaving public - because this class is shrinking to be almost nothing
|
||||||
|
|
||||||
/** pool is the pool we will alloc our rx packets from
|
/** pool is the pool we will alloc our rx packets from
|
||||||
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
|
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
|
||||||
@ -86,7 +87,6 @@ public:
|
|||||||
void reloadConfig();
|
void reloadConfig();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// RHDatagram manager;
|
// RHDatagram manager;
|
||||||
// RHReliableDatagram manager; // don't use mesh yet
|
// RHReliableDatagram manager; // don't use mesh yet
|
||||||
RHMesh manager;
|
RHMesh manager;
|
||||||
@ -98,5 +98,3 @@ private:
|
|||||||
/// enqueue a received packet in rxDest
|
/// enqueue a received packet in rxDest
|
||||||
void handleReceive(MeshPacket *p);
|
void handleReceive(MeshPacket *p);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,37 +2,41 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "main.h"
|
|
||||||
#include "mesh-pb-constants.h"
|
|
||||||
#include "MeshService.h"
|
|
||||||
#include "MeshBluetoothService.h"
|
|
||||||
#include "NodeDB.h"
|
|
||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
|
#include "MeshBluetoothService.h"
|
||||||
|
#include "MeshService.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
#include "Periodic.h"
|
#include "Periodic.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "mesh-pb-constants.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
receivedPacketQueue - this is a queue of messages we've received from the mesh, which we are keeping to deliver to the phone.
|
receivedPacketQueue - this is a queue of messages we've received from the mesh, which we are keeping to deliver to the phone.
|
||||||
It is implemented with a FreeRTos queue (wrapped with a little RTQueue class) of pointers to MeshPacket protobufs (which were alloced with new).
|
It is implemented with a FreeRTos queue (wrapped with a little RTQueue class) of pointers to MeshPacket protobufs (which were
|
||||||
After a packet ptr is removed from the queue and processed it should be deleted. (eventually we should move sent packets into a 'sentToPhone' queue
|
alloced with new). After a packet ptr is removed from the queue and processed it should be deleted. (eventually we should move
|
||||||
of packets we can delete just as soon as we are sure the phone has acked those packets - when the phone writes to FromNum)
|
sent packets into a 'sentToPhone' queue of packets we can delete just as soon as we are sure the phone has acked those packets -
|
||||||
|
when the phone writes to FromNum)
|
||||||
|
|
||||||
mesh - an instance of Mesh class. Which manages the interface to the mesh radio library, reception of packets from other nodes, arbitrating to select
|
mesh - an instance of Mesh class. Which manages the interface to the mesh radio library, reception of packets from other nodes,
|
||||||
a node number and keeping the current nodedb.
|
arbitrating to select a node number and keeping the current nodedb.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Broadcast when a newly powered mesh node wants to find a node num it can use
|
/* Broadcast when a newly powered mesh node wants to find a node num it can use
|
||||||
|
|
||||||
The algoritm is as follows:
|
The algoritm is as follows:
|
||||||
* when a node starts up, it broadcasts their user and the normal flow is for all other nodes to reply with their User as well (so the new node can build its node db)
|
* when a node starts up, it broadcasts their user and the normal flow is for all other nodes to reply with their User as well (so
|
||||||
* If a node ever receives a User (not just the first broadcast) message where the sender node number equals our node number, that indicates a collision has occurred and the following steps should happen:
|
the new node can build its node db)
|
||||||
|
* If a node ever receives a User (not just the first broadcast) message where the sender node number equals our node number, that
|
||||||
|
indicates a collision has occurred and the following steps should happen:
|
||||||
|
|
||||||
If the receiving node (that was already in the mesh)'s macaddr is LOWER than the new User who just tried to sign in: it gets to keep its nodenum. We send a broadcast message
|
If the receiving node (that was already in the mesh)'s macaddr is LOWER than the new User who just tried to sign in: it gets to
|
||||||
of OUR User (we use a broadcast so that the other node can receive our message, considering we have the same id - it also serves to let observers correct their nodedb) - this case is rare so it should be okay.
|
keep its nodenum. We send a broadcast message of OUR User (we use a broadcast so that the other node can receive our message,
|
||||||
|
considering we have the same id - it also serves to let observers correct their nodedb) - this case is rare so it should be okay.
|
||||||
|
|
||||||
If any node receives a User where the macaddr is GTE than their local macaddr, they have been vetoed and should pick a new random nodenum (filtering against whatever it knows about the nodedb) and
|
If any node receives a User where the macaddr is GTE than their local macaddr, they have been vetoed and should pick a new random
|
||||||
rebroadcast their User.
|
nodenum (filtering against whatever it knows about the nodedb) and rebroadcast their User.
|
||||||
|
|
||||||
FIXME in the initial proof of concept we just skip the entire want/deny flow and just hand pick node numbers at first.
|
FIXME in the initial proof of concept we just skip the entire want/deny flow and just hand pick node numbers at first.
|
||||||
*/
|
*/
|
||||||
@ -40,15 +44,15 @@ FIXME in the initial proof of concept we just skip the entire want/deny flow and
|
|||||||
MeshService service;
|
MeshService service;
|
||||||
|
|
||||||
// I think this is right, one packet for each of the three fifos + one packet being currently assembled for TX or RX
|
// I think this is right, one packet for each of the three fifos + one packet being currently assembled for TX or RX
|
||||||
#define MAX_PACKETS (MAX_RX_TOPHONE + MAX_RX_FROMRADIO + MAX_TX_QUEUE + 2) // max number of packets which can be in flight (either queued from reception or queued for sending)
|
#define MAX_PACKETS \
|
||||||
|
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + MAX_TX_QUEUE + \
|
||||||
|
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
|
||||||
|
|
||||||
#define MAX_RX_FROMRADIO 4 // max number of packets destined to our queue, we dispatch packets quickly so it doesn't need to be big
|
#define MAX_RX_FROMRADIO \
|
||||||
|
4 // max number of packets destined to our queue, we dispatch packets quickly so it doesn't need to be big
|
||||||
|
|
||||||
MeshService::MeshService()
|
MeshService::MeshService()
|
||||||
: packetPool(MAX_PACKETS),
|
: packetPool(MAX_PACKETS), toPhoneQueue(MAX_RX_TOPHONE), fromRadioQueue(MAX_RX_FROMRADIO), fromNum(0),
|
||||||
toPhoneQueue(MAX_RX_TOPHONE),
|
|
||||||
fromRadioQueue(MAX_RX_FROMRADIO),
|
|
||||||
fromNum(0),
|
|
||||||
radio(packetPool, fromRadioQueue)
|
radio(packetPool, fromRadioQueue)
|
||||||
{
|
{
|
||||||
// assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro
|
// assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro
|
||||||
@ -88,29 +92,25 @@ MeshPacket *MeshService::handleFromRadioUser(MeshPacket *mp)
|
|||||||
// we win if we have a lower macaddr
|
// we win if we have a lower macaddr
|
||||||
bool weWin = memcmp(&owner.macaddr, &mp->payload.variant.user.macaddr, sizeof(owner.macaddr)) < 0;
|
bool weWin = memcmp(&owner.macaddr, &mp->payload.variant.user.macaddr, sizeof(owner.macaddr)) < 0;
|
||||||
|
|
||||||
if (isCollision)
|
if (isCollision) {
|
||||||
{
|
if (weWin) {
|
||||||
if (weWin)
|
|
||||||
{
|
|
||||||
DEBUG_MSG("NOTE! Received a nodenum collision and we are vetoing\n");
|
DEBUG_MSG("NOTE! Received a nodenum collision and we are vetoing\n");
|
||||||
|
|
||||||
packetPool.release(mp); // discard it
|
packetPool.release(mp); // discard it
|
||||||
mp = NULL;
|
mp = NULL;
|
||||||
|
|
||||||
sendOurOwner(); // send our owner as a _broadcast_ because that other guy is mistakenly using our nodenum
|
sendOurOwner(); // send our owner as a _broadcast_ because that other guy is mistakenly using our nodenum
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// we lost, we need to try for a new nodenum!
|
// we lost, we need to try for a new nodenum!
|
||||||
DEBUG_MSG("NOTE! Received a nodenum collision we lost, so picking a new nodenum\n");
|
DEBUG_MSG("NOTE! Received a nodenum collision we lost, so picking a new nodenum\n");
|
||||||
nodeDB.updateFrom(*mp); // update the DB early - before trying to repick (so we don't select the same node number again)
|
nodeDB.updateFrom(
|
||||||
|
*mp); // update the DB early - before trying to repick (so we don't select the same node number again)
|
||||||
nodeDB.pickNewNodeNum();
|
nodeDB.pickNewNodeNum();
|
||||||
sendOurOwner(); // broadcast our new attempt at a node number
|
sendOurOwner(); // broadcast our new attempt at a node number
|
||||||
}
|
}
|
||||||
}
|
} else if (wasBroadcast) {
|
||||||
else if (wasBroadcast)
|
// If we haven't yet abandoned the packet and it was a broadcast, reply (just to them) with our User record so they can
|
||||||
{
|
// build their DB
|
||||||
// If we haven't yet abandoned the packet and it was a broadcast, reply (just to them) with our User record so they can build their DB
|
|
||||||
|
|
||||||
// Someone just sent us a User, reply with our Owner
|
// Someone just sent us a User, reply with our Owner
|
||||||
DEBUG_MSG("Received broadcast Owner from 0x%x, replying with our owner\n", mp->from);
|
DEBUG_MSG("Received broadcast Owner from 0x%x, replying with our owner\n", mp->from);
|
||||||
@ -126,12 +126,10 @@ MeshPacket *MeshService::handleFromRadioUser(MeshPacket *mp)
|
|||||||
|
|
||||||
void MeshService::handleIncomingPosition(MeshPacket *mp)
|
void MeshService::handleIncomingPosition(MeshPacket *mp)
|
||||||
{
|
{
|
||||||
if (mp->has_payload && mp->payload.which_variant == SubPacket_position_tag)
|
if (mp->has_payload && mp->payload.which_variant == SubPacket_position_tag) {
|
||||||
{
|
|
||||||
DEBUG_MSG("handled incoming position time=%u\n", mp->payload.variant.position.time);
|
DEBUG_MSG("handled incoming position time=%u\n", mp->payload.variant.position.time);
|
||||||
|
|
||||||
if (mp->payload.variant.position.time)
|
if (mp->payload.variant.position.time) {
|
||||||
{
|
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
uint32_t secs = mp->payload.variant.position.time;
|
uint32_t secs = mp->payload.variant.position.time;
|
||||||
|
|
||||||
@ -153,21 +151,18 @@ void MeshService::handleFromRadio(MeshPacket *mp)
|
|||||||
if (!myNodeInfo.has_gps)
|
if (!myNodeInfo.has_gps)
|
||||||
handleIncomingPosition(mp);
|
handleIncomingPosition(mp);
|
||||||
|
|
||||||
if (mp->has_payload && mp->payload.which_variant == SubPacket_user_tag)
|
if (mp->has_payload && mp->payload.which_variant == SubPacket_user_tag) {
|
||||||
{
|
|
||||||
mp = handleFromRadioUser(mp);
|
mp = handleFromRadioUser(mp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we veto a received User packet, we don't put it into the DB or forward it to the phone (to prevent confusing it)
|
// If we veto a received User packet, we don't put it into the DB or forward it to the phone (to prevent confusing it)
|
||||||
if (mp)
|
if (mp) {
|
||||||
{
|
|
||||||
DEBUG_MSG("Forwarding to phone, from=0x%x, rx_time=%u\n", mp->from, mp->rx_time);
|
DEBUG_MSG("Forwarding to phone, from=0x%x, rx_time=%u\n", mp->from, mp->rx_time);
|
||||||
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
|
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
|
||||||
|
|
||||||
fromNum++;
|
fromNum++;
|
||||||
|
|
||||||
if (toPhoneQueue.numFree() == 0)
|
if (toPhoneQueue.numFree() == 0) {
|
||||||
{
|
|
||||||
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
|
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
|
||||||
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
|
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
|
||||||
if (d)
|
if (d)
|
||||||
@ -177,8 +172,7 @@ void MeshService::handleFromRadio(MeshPacket *mp)
|
|||||||
|
|
||||||
if (mp->payload.want_response)
|
if (mp->payload.want_response)
|
||||||
sendNetworkPing(mp->from);
|
sendNetworkPing(mp->from);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
DEBUG_MSG("Dropping vetoed User message\n");
|
DEBUG_MSG("Dropping vetoed User message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,8 +180,7 @@ void MeshService::handleFromRadio()
|
|||||||
{
|
{
|
||||||
MeshPacket *mp;
|
MeshPacket *mp;
|
||||||
uint32_t oldFromNum = fromNum;
|
uint32_t oldFromNum = fromNum;
|
||||||
while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL)
|
while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL) {
|
||||||
{
|
|
||||||
handleFromRadio(mp);
|
handleFromRadio(mp);
|
||||||
}
|
}
|
||||||
if (oldFromNum != fromNum) // We don't want to generate extra notifies for multiple new packets
|
if (oldFromNum != fromNum) // We don't want to generate extra notifies for multiple new packets
|
||||||
@ -227,23 +220,20 @@ void MeshService::handleToRadio(std::string s)
|
|||||||
{
|
{
|
||||||
static ToRadio r; // this is a static scratch object, any data must be copied elsewhere before returning
|
static ToRadio r; // this is a static scratch object, any data must be copied elsewhere before returning
|
||||||
|
|
||||||
if (pb_decode_from_bytes((const uint8_t *)s.c_str(), s.length(), ToRadio_fields, &r))
|
if (pb_decode_from_bytes((const uint8_t *)s.c_str(), s.length(), ToRadio_fields, &r)) {
|
||||||
{
|
switch (r.which_variant) {
|
||||||
switch (r.which_variant)
|
case ToRadio_packet_tag: {
|
||||||
{
|
|
||||||
case ToRadio_packet_tag:
|
|
||||||
{
|
|
||||||
// If our phone is sending a position, see if we can use it to set our RTC
|
// If our phone is sending a position, see if we can use it to set our RTC
|
||||||
handleIncomingPosition(&r.variant.packet); // If it is a position packet, perhaps set our clock
|
handleIncomingPosition(&r.variant.packet); // If it is a position packet, perhaps set our clock
|
||||||
|
|
||||||
r.variant.packet.rx_time = gps.getValidTime(); // Record the time the packet arrived from the phone (so we update our nodedb for the local node)
|
r.variant.packet.rx_time = gps.getValidTime(); // Record the time the packet arrived from the phone (so we update our
|
||||||
|
// nodedb for the local node)
|
||||||
|
|
||||||
// Send the packet into the mesh
|
// Send the packet into the mesh
|
||||||
sendToMesh(packetPool.allocCopy(r.variant.packet));
|
sendToMesh(packetPool.allocCopy(r.variant.packet));
|
||||||
|
|
||||||
bool loopback = false; // if true send any packet the phone sends back itself (for testing)
|
bool loopback = false; // if true send any packet the phone sends back itself (for testing)
|
||||||
if (loopback)
|
if (loopback) {
|
||||||
{
|
|
||||||
MeshPacket *mp = packetPool.allocCopy(r.variant.packet);
|
MeshPacket *mp = packetPool.allocCopy(r.variant.packet);
|
||||||
handleFromRadio(mp);
|
handleFromRadio(mp);
|
||||||
bluetoothNotifyFromNum(fromNum); // tell the phone a new packet arrived
|
bluetoothNotifyFromNum(fromNum); // tell the phone a new packet arrived
|
||||||
@ -254,8 +244,7 @@ void MeshService::handleToRadio(std::string s)
|
|||||||
DEBUG_MSG("Error: unexpected ToRadio variant\n");
|
DEBUG_MSG("Error: unexpected ToRadio variant\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
DEBUG_MSG("Error: ignoring malformed toradio\n");
|
DEBUG_MSG("Error: ignoring malformed toradio\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,10 +253,10 @@ void MeshService::sendToMesh(MeshPacket *p)
|
|||||||
{
|
{
|
||||||
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
|
nodeDB.updateFrom(*p); // update our local DB for this packet (because phone might have sent position packets etc...)
|
||||||
|
|
||||||
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other nodes shouldn't trust it anyways)
|
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other
|
||||||
// Note: for now, we allow a device with a local GPS to include the time, so that gpsless devices can get time.
|
// nodes shouldn't trust it anyways) Note: for now, we allow a device with a local GPS to include the time, so that gpsless
|
||||||
if (p->has_payload && p->payload.which_variant == SubPacket_position_tag)
|
// devices can get time.
|
||||||
{
|
if (p->has_payload && p->payload.which_variant == SubPacket_position_tag) {
|
||||||
if (!myNodeInfo.has_gps)
|
if (!myNodeInfo.has_gps)
|
||||||
p->payload.variant.position.time = 0;
|
p->payload.variant.position.time = 0;
|
||||||
else
|
else
|
||||||
@ -277,8 +266,7 @@ void MeshService::sendToMesh(MeshPacket *p)
|
|||||||
// If the phone sent a packet just to us, don't send it out into the network
|
// If the phone sent a packet just to us, don't send it out into the network
|
||||||
if (p->to == nodeDB.getNodeNum())
|
if (p->to == nodeDB.getNodeNum())
|
||||||
DEBUG_MSG("Dropping locally processed message\n");
|
DEBUG_MSG("Dropping locally processed message\n");
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
|
// Note: We might return !OK if our fifo was full, at that point the only option we have is to drop it
|
||||||
if (radio.send(p) != ERRNO_OK)
|
if (radio.send(p) != ERRNO_OK)
|
||||||
DEBUG_MSG("Dropped packet because send queue was full!\n");
|
DEBUG_MSG("Dropped packet because send queue was full!\n");
|
||||||
@ -319,7 +307,8 @@ void MeshService::sendOurPosition(NodeNum dest)
|
|||||||
p->to = dest;
|
p->to = dest;
|
||||||
p->payload.which_variant = SubPacket_position_tag;
|
p->payload.which_variant = SubPacket_position_tag;
|
||||||
p->payload.variant.position = node->position;
|
p->payload.variant.position = node->position;
|
||||||
p->payload.variant.position.time = gps.getValidTime(); // This nodedb timestamp might be stale, so update it if our clock is valid.
|
p->payload.variant.position.time =
|
||||||
|
gps.getValidTime(); // This nodedb timestamp might be stale, so update it if our clock is valid.
|
||||||
sendToMesh(p);
|
sendToMesh(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,15 +331,12 @@ void MeshService::onGPSChanged()
|
|||||||
// We limit our GPS broadcasts to a max rate
|
// We limit our GPS broadcasts to a max rate
|
||||||
static uint32_t lastGpsSend;
|
static uint32_t lastGpsSend;
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
if (lastGpsSend == 0 || now - lastGpsSend > radioConfig.preferences.position_broadcast_secs * 1000)
|
if (lastGpsSend == 0 || now - lastGpsSend > radioConfig.preferences.position_broadcast_secs * 1000) {
|
||||||
{
|
|
||||||
lastGpsSend = now;
|
lastGpsSend = now;
|
||||||
DEBUG_MSG("Sending position to mesh\n");
|
DEBUG_MSG("Sending position to mesh\n");
|
||||||
|
|
||||||
sendToMesh(p);
|
sendToMesh(p);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// We don't need to send this packet to anyone else, but it still serves as a nice uniform way to update our local state
|
// We don't need to send this packet to anyone else, but it still serves as a nice uniform way to update our local state
|
||||||
nodeDB.updateFrom(*p);
|
nodeDB.updateFrom(*p);
|
||||||
|
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "mesh.pb.h"
|
|
||||||
#include "MeshRadio.h"
|
|
||||||
#include "PointerQueue.h"
|
|
||||||
#include "MemoryPool.h"
|
#include "MemoryPool.h"
|
||||||
|
#include "MeshRadio.h"
|
||||||
#include "Observer.h"
|
#include "Observer.h"
|
||||||
|
#include "PointerQueue.h"
|
||||||
|
#include "mesh.pb.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
|
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
|
||||||
@ -31,7 +31,6 @@ class MeshService: private Observer
|
|||||||
uint32_t fromNum;
|
uint32_t fromNum;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MeshRadio radio;
|
MeshRadio radio;
|
||||||
|
|
||||||
MeshService();
|
MeshService();
|
||||||
@ -60,17 +59,20 @@ public:
|
|||||||
/// Allocate and return a meshpacket which defaults as send to broadcast from the current node.
|
/// Allocate and return a meshpacket which defaults as send to broadcast from the current node.
|
||||||
MeshPacket *allocForSending();
|
MeshPacket *allocForSending();
|
||||||
|
|
||||||
/// Called when the user wakes up our GUI, normally sends our latest location to the mesh (if we have it), otherwise at least sends our owner
|
/// Called when the user wakes up our GUI, normally sends our latest location to the mesh (if we have it), otherwise at least
|
||||||
|
/// sends our owner
|
||||||
void sendNetworkPing(NodeNum dest = NODENUM_BROADCAST);
|
void sendNetworkPing(NodeNum dest = NODENUM_BROADCAST);
|
||||||
|
|
||||||
/// Send our owner info to a particular node
|
/// Send our owner info to a particular node
|
||||||
void sendOurOwner(NodeNum dest = NODENUM_BROADCAST);
|
void sendOurOwner(NodeNum dest = NODENUM_BROADCAST);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Broadcasts our last known position
|
/// Broadcasts our last known position
|
||||||
void sendOurPosition(NodeNum dest = NODENUM_BROADCAST);
|
void sendOurPosition(NodeNum dest = NODENUM_BROADCAST);
|
||||||
|
|
||||||
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after sending.
|
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after
|
||||||
/// This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb cache
|
/// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb
|
||||||
|
/// cache
|
||||||
void sendToMesh(MeshPacket *p);
|
void sendToMesh(MeshPacket *p);
|
||||||
|
|
||||||
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
||||||
@ -92,4 +94,3 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern MeshService service;
|
extern MeshService service;
|
||||||
|
|
||||||
|
@ -5,13 +5,13 @@
|
|||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
#include "SPIFFS.h"
|
#include "SPIFFS.h"
|
||||||
|
|
||||||
#include <pb_encode.h>
|
#include "GPS.h"
|
||||||
#include <pb_decode.h>
|
#include "NodeDB.h"
|
||||||
|
#include "PowerFSM.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include "NodeDB.h"
|
#include <pb_decode.h>
|
||||||
#include "GPS.h"
|
#include <pb_encode.h>
|
||||||
#include "PowerFSM.h"
|
|
||||||
|
|
||||||
NodeDB nodeDB;
|
NodeDB nodeDB;
|
||||||
|
|
||||||
@ -41,9 +41,7 @@ User &owner = devicestate.owner;
|
|||||||
|
|
||||||
static uint8_t ourMacAddr[6];
|
static uint8_t ourMacAddr[6];
|
||||||
|
|
||||||
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count)
|
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodeDB::init()
|
void NodeDB::init()
|
||||||
{
|
{
|
||||||
@ -78,8 +76,8 @@ void NodeDB::init()
|
|||||||
|
|
||||||
// Init our blank owner info to reasonable defaults
|
// Init our blank owner info to reasonable defaults
|
||||||
esp_efuse_mac_get_default(ourMacAddr);
|
esp_efuse_mac_get_default(ourMacAddr);
|
||||||
sprintf(owner.id, "!%02x%02x%02x%02x%02x%02x", ourMacAddr[0],
|
sprintf(owner.id, "!%02x%02x%02x%02x%02x%02x", ourMacAddr[0], ourMacAddr[1], ourMacAddr[2], ourMacAddr[3], ourMacAddr[4],
|
||||||
ourMacAddr[1], ourMacAddr[2], ourMacAddr[3], ourMacAddr[4], ourMacAddr[5]);
|
ourMacAddr[5]);
|
||||||
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
|
memcpy(owner.macaddr, ourMacAddr, sizeof(owner.macaddr));
|
||||||
|
|
||||||
// make each node start with ad different random seed (but okay that the sequence is the same each boot)
|
// make each node start with ad different random seed (but okay that the sequence is the same each boot)
|
||||||
@ -122,8 +120,7 @@ void NodeDB::pickNewNodeNum()
|
|||||||
r = NUM_RESERVED; // don't pick a reserved node number
|
r = NUM_RESERVED; // don't pick a reserved node number
|
||||||
|
|
||||||
NodeInfo *found;
|
NodeInfo *found;
|
||||||
while ((found = getNode(r)) && memcmp(found->user.macaddr, owner.macaddr, sizeof(owner.macaddr)))
|
while ((found = getNode(r)) && memcmp(found->user.macaddr, owner.macaddr, sizeof(owner.macaddr))) {
|
||||||
{
|
|
||||||
NodeNum n = random(NUM_RESERVED, NODENUM_BROADCAST); // try a new random choice
|
NodeNum n = random(NUM_RESERVED, NODENUM_BROADCAST); // try a new random choice
|
||||||
DEBUG_MSG("NOTE! Our desired nodenum 0x%x is in use, so trying for 0x%x\n", r, n);
|
DEBUG_MSG("NOTE! Our desired nodenum 0x%x is in use, so trying for 0x%x\n", r, n);
|
||||||
r = n;
|
r = n;
|
||||||
@ -140,25 +137,20 @@ void NodeDB::loadFromDisk()
|
|||||||
static DeviceState scratch;
|
static DeviceState scratch;
|
||||||
|
|
||||||
File f = FS.open(preffile);
|
File f = FS.open(preffile);
|
||||||
if (f)
|
if (f) {
|
||||||
{
|
|
||||||
DEBUG_MSG("Loading saved preferences\n");
|
DEBUG_MSG("Loading saved preferences\n");
|
||||||
pb_istream_t stream = {&readcb, &f, DeviceState_size};
|
pb_istream_t stream = {&readcb, &f, DeviceState_size};
|
||||||
|
|
||||||
// DEBUG_MSG("Preload channel name=%s\n", channelSettings.name);
|
// DEBUG_MSG("Preload channel name=%s\n", channelSettings.name);
|
||||||
|
|
||||||
memset(&scratch, 0, sizeof(scratch));
|
memset(&scratch, 0, sizeof(scratch));
|
||||||
if (!pb_decode(&stream, DeviceState_fields, &scratch))
|
if (!pb_decode(&stream, DeviceState_fields, &scratch)) {
|
||||||
{
|
|
||||||
DEBUG_MSG("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream));
|
DEBUG_MSG("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream));
|
||||||
// FIXME - report failure to phone
|
// FIXME - report failure to phone
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
if (scratch.version < DEVICESTATE_MIN_VER)
|
if (scratch.version < DEVICESTATE_MIN_VER)
|
||||||
DEBUG_MSG("Warn: devicestate is old, discarding\n");
|
DEBUG_MSG("Warn: devicestate is old, discarding\n");
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
DEBUG_MSG("Loaded saved preferences version %d\n", scratch.version);
|
DEBUG_MSG("Loaded saved preferences version %d\n", scratch.version);
|
||||||
devicestate = scratch;
|
devicestate = scratch;
|
||||||
}
|
}
|
||||||
@ -167,9 +159,7 @@ void NodeDB::loadFromDisk()
|
|||||||
}
|
}
|
||||||
|
|
||||||
f.close();
|
f.close();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_MSG("No saved preferences found\n");
|
DEBUG_MSG("No saved preferences found\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,8 +167,7 @@ void NodeDB::loadFromDisk()
|
|||||||
void NodeDB::saveToDisk()
|
void NodeDB::saveToDisk()
|
||||||
{
|
{
|
||||||
File f = FS.open(preftmp, "w");
|
File f = FS.open(preftmp, "w");
|
||||||
if (f)
|
if (f) {
|
||||||
{
|
|
||||||
DEBUG_MSG("Writing preferences\n");
|
DEBUG_MSG("Writing preferences\n");
|
||||||
|
|
||||||
pb_ostream_t stream = {&writecb, &f, SIZE_MAX, 0};
|
pb_ostream_t stream = {&writecb, &f, SIZE_MAX, 0};
|
||||||
@ -186,8 +175,7 @@ void NodeDB::saveToDisk()
|
|||||||
// DEBUG_MSG("Presave channel name=%s\n", channelSettings.name);
|
// DEBUG_MSG("Presave channel name=%s\n", channelSettings.name);
|
||||||
|
|
||||||
devicestate.version = DEVICESTATE_CUR_VER;
|
devicestate.version = DEVICESTATE_CUR_VER;
|
||||||
if (!pb_encode(&stream, DeviceState_fields, &devicestate))
|
if (!pb_encode(&stream, DeviceState_fields, &devicestate)) {
|
||||||
{
|
|
||||||
DEBUG_MSG("Error: can't write protobuf %s\n", PB_GET_ERROR(&stream));
|
DEBUG_MSG("Error: can't write protobuf %s\n", PB_GET_ERROR(&stream));
|
||||||
// FIXME - report failure to phone
|
// FIXME - report failure to phone
|
||||||
}
|
}
|
||||||
@ -199,9 +187,7 @@ void NodeDB::saveToDisk()
|
|||||||
DEBUG_MSG("Warning: Can't remove old pref file\n");
|
DEBUG_MSG("Warning: Can't remove old pref file\n");
|
||||||
if (!FS.rename(preftmp, preffile))
|
if (!FS.rename(preftmp, preffile))
|
||||||
DEBUG_MSG("Error: can't rename new pref file\n");
|
DEBUG_MSG("Error: can't rename new pref file\n");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_MSG("ERROR: can't write prefs\n"); // FIXME report to app
|
DEBUG_MSG("ERROR: can't write prefs\n"); // FIXME report to app
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,8 +231,7 @@ size_t NodeDB::getNumOnlineNodes()
|
|||||||
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
|
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
|
||||||
void NodeDB::updateFrom(const MeshPacket &mp)
|
void NodeDB::updateFrom(const MeshPacket &mp)
|
||||||
{
|
{
|
||||||
if (mp.has_payload)
|
if (mp.has_payload) {
|
||||||
{
|
|
||||||
const SubPacket &p = mp.payload;
|
const SubPacket &p = mp.payload;
|
||||||
DEBUG_MSG("Update DB node 0x%x for variant %d, rx_time=%u\n", mp.from, p.which_variant, mp.rx_time);
|
DEBUG_MSG("Update DB node 0x%x for variant %d, rx_time=%u\n", mp.from, p.which_variant, mp.rx_time);
|
||||||
|
|
||||||
@ -256,16 +241,13 @@ void NodeDB::updateFrom(const MeshPacket &mp)
|
|||||||
if (oldNumNodes != *numNodes)
|
if (oldNumNodes != *numNodes)
|
||||||
updateGUI = true; // we just created a nodeinfo
|
updateGUI = true; // we just created a nodeinfo
|
||||||
|
|
||||||
if (mp.rx_time)
|
if (mp.rx_time) { // if the packet has a valid timestamp use it to update our last_seen
|
||||||
{ // if the packet has a valid timestamp use it to update our last_seen
|
|
||||||
info->has_position = true; // at least the time is valid
|
info->has_position = true; // at least the time is valid
|
||||||
info->position.time = mp.rx_time;
|
info->position.time = mp.rx_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (p.which_variant)
|
switch (p.which_variant) {
|
||||||
{
|
case SubPacket_position_tag: {
|
||||||
case SubPacket_position_tag:
|
|
||||||
{
|
|
||||||
// we carefully preserve the old time, because we always trust our local timestamps more
|
// we carefully preserve the old time, because we always trust our local timestamps more
|
||||||
uint32_t oldtime = info->position.time;
|
uint32_t oldtime = info->position.time;
|
||||||
info->position = p.variant.position;
|
info->position = p.variant.position;
|
||||||
@ -275,14 +257,12 @@ void NodeDB::updateFrom(const MeshPacket &mp)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SubPacket_data_tag:
|
case SubPacket_data_tag: {
|
||||||
{
|
|
||||||
// Keep a copy of the most recent text message.
|
// Keep a copy of the most recent text message.
|
||||||
if (p.variant.data.typ == Data_Type_CLEAR_TEXT)
|
if (p.variant.data.typ == Data_Type_CLEAR_TEXT) {
|
||||||
{
|
DEBUG_MSG("Received text msg from=0%0x, msg=%.*s\n", mp.from, p.variant.data.payload.size,
|
||||||
DEBUG_MSG("Received text msg from=0%0x, msg=%.*s\n", mp.from, p.variant.data.payload.size, p.variant.data.payload.bytes);
|
p.variant.data.payload.bytes);
|
||||||
if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum())
|
if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) {
|
||||||
{
|
|
||||||
// We only store/display messages destined for us.
|
// We only store/display messages destined for us.
|
||||||
devicestate.rx_text_message = mp;
|
devicestate.rx_text_message = mp;
|
||||||
devicestate.has_rx_text_message = true;
|
devicestate.has_rx_text_message = true;
|
||||||
@ -293,18 +273,17 @@ void NodeDB::updateFrom(const MeshPacket &mp)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SubPacket_user_tag:
|
case SubPacket_user_tag: {
|
||||||
{
|
|
||||||
DEBUG_MSG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
|
DEBUG_MSG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
|
||||||
|
|
||||||
bool changed = memcmp(&info->user, &p.variant.user, sizeof(info->user)); // Both of these blocks start as filled with zero so I think this is okay
|
bool changed = memcmp(&info->user, &p.variant.user,
|
||||||
|
sizeof(info->user)); // Both of these blocks start as filled with zero so I think this is okay
|
||||||
|
|
||||||
info->user = p.variant.user;
|
info->user = p.variant.user;
|
||||||
DEBUG_MSG("updating changed=%d user %s/%s/%s\n", changed, info->user.id, info->user.long_name, info->user.short_name);
|
DEBUG_MSG("updating changed=%d user %s/%s/%s\n", changed, info->user.id, info->user.long_name, info->user.short_name);
|
||||||
info->has_user = true;
|
info->has_user = true;
|
||||||
|
|
||||||
if (changed)
|
if (changed) {
|
||||||
{
|
|
||||||
updateGUIforNode = info;
|
updateGUIforNode = info;
|
||||||
powerFSM.trigger(EVENT_NODEDB_UPDATED);
|
powerFSM.trigger(EVENT_NODEDB_UPDATED);
|
||||||
|
|
||||||
@ -337,8 +316,7 @@ NodeInfo *NodeDB::getOrCreateNode(NodeNum n)
|
|||||||
{
|
{
|
||||||
NodeInfo *info = getNode(n);
|
NodeInfo *info = getNode(n);
|
||||||
|
|
||||||
if (!info)
|
if (!info) {
|
||||||
{
|
|
||||||
// add the node
|
// add the node
|
||||||
assert(*numNodes < MAX_NUM_NODES);
|
assert(*numNodes < MAX_NUM_NODES);
|
||||||
info = &nodes[(*numNodes)++];
|
info = &nodes[(*numNodes)++];
|
||||||
|
19
src/NodeDB.h
19
src/NodeDB.h
@ -3,8 +3,8 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "mesh-pb-constants.h"
|
|
||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
|
#include "mesh-pb-constants.h"
|
||||||
|
|
||||||
extern DeviceState devicestate;
|
extern DeviceState devicestate;
|
||||||
extern MyNodeInfo &myNodeInfo;
|
extern MyNodeInfo &myNodeInfo;
|
||||||
@ -56,10 +56,11 @@ public:
|
|||||||
// bool handleWantNodeNum(NodeNum n);
|
// bool handleWantNodeNum(NodeNum n);
|
||||||
|
|
||||||
/* void handleDenyNodeNum(NodeNum FIXME read mesh proto docs, perhaps picking a random node num is not a great idea
|
/* void handleDenyNodeNum(NodeNum FIXME read mesh proto docs, perhaps picking a random node num is not a great idea
|
||||||
and instead we should use a special 'im unconfigured node number' and include our desired node number in the wantnum message. the
|
and instead we should use a special 'im unconfigured node number' and include our desired node number in the wantnum message.
|
||||||
unconfigured node num would only be used while initially joining the mesh so low odds of conflicting (especially if we randomly select
|
the unconfigured node num would only be used while initially joining the mesh so low odds of conflicting (especially if we
|
||||||
from a small number of nodenums which can be used temporarily for this operation). figure out what the lower level
|
randomly select from a small number of nodenums which can be used temporarily for this operation). figure out what the lower
|
||||||
mesh sw does if it does conflict? would it be better for people who are replying with denynode num to just broadcast their denial?)
|
level mesh sw does if it does conflict? would it be better for people who are replying with denynode num to just broadcast
|
||||||
|
their denial?)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// Called from bluetooth when the user wants to start reading the node DB from scratch.
|
/// Called from bluetooth when the user wants to start reading the node DB from scratch.
|
||||||
@ -74,13 +75,16 @@ public:
|
|||||||
/// Find a node in our DB, return null for missing
|
/// Find a node in our DB, return null for missing
|
||||||
NodeInfo *getNode(NodeNum n);
|
NodeInfo *getNode(NodeNum n);
|
||||||
|
|
||||||
NodeInfo *getNodeByIndex(size_t x) { assert(x < *numNodes); return &nodes[x]; }
|
NodeInfo *getNodeByIndex(size_t x)
|
||||||
|
{
|
||||||
|
assert(x < *numNodes);
|
||||||
|
return &nodes[x];
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the number of nodes we've heard from recently (within the last 2 hrs?)
|
/// Return the number of nodes we've heard from recently (within the last 2 hrs?)
|
||||||
size_t getNumOnlineNodes();
|
size_t getNumOnlineNodes();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// Find a node in our DB, create an empty NodeInfo if missing
|
/// Find a node in our DB, create an empty NodeInfo if missing
|
||||||
NodeInfo *getOrCreateNode(NodeNum n);
|
NodeInfo *getOrCreateNode(NodeNum n);
|
||||||
|
|
||||||
@ -89,4 +93,3 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern NodeDB nodeDB;
|
extern NodeDB nodeDB;
|
||||||
|
|
||||||
|
@ -30,20 +30,12 @@ class Observable
|
|||||||
public:
|
public:
|
||||||
void notifyObservers()
|
void notifyObservers()
|
||||||
{
|
{
|
||||||
for (std::list<Observer *>::const_iterator iterator = observers.begin(); iterator != observers.end(); ++iterator)
|
for (std::list<Observer *>::const_iterator iterator = observers.begin(); iterator != observers.end(); ++iterator) {
|
||||||
{
|
|
||||||
(*iterator)->onNotify(this);
|
(*iterator)->onNotify(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addObserver(Observer *o)
|
void addObserver(Observer *o) { observers.push_back(o); }
|
||||||
{
|
|
||||||
observers.push_back(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeObserver(Observer *o)
|
void removeObserver(Observer *o) { observers.remove(o); }
|
||||||
{
|
|
||||||
observers.remove(o);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include "PeriodicTask.h"
|
#include "PeriodicTask.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Periodically invoke a callback.
|
* Periodically invoke a callback.
|
||||||
@ -17,6 +17,5 @@ public:
|
|||||||
Periodic(uint32_t (*_callback)()) : callback(_callback) {}
|
Periodic(uint32_t (*_callback)()) : callback(_callback) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void doTask();
|
void doTask();
|
||||||
};
|
};
|
||||||
|
@ -5,13 +5,10 @@
|
|||||||
/**
|
/**
|
||||||
* A wrapper for freertos queues that assumes each element is a pointer
|
* A wrapper for freertos queues that assumes each element is a pointer
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T> class PointerQueue : public TypedQueue<T *>
|
||||||
class PointerQueue : public TypedQueue<T *>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PointerQueue(int maxElements) : TypedQueue<T *>(maxElements)
|
PointerQueue(int maxElements) : TypedQueue<T *>(maxElements) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns a ptr or null if the queue was empty
|
// returns a ptr or null if the queue was empty
|
||||||
T *dequeuePtr(TickType_t maxWait = portMAX_DELAY)
|
T *dequeuePtr(TickType_t maxWait = portMAX_DELAY)
|
||||||
|
@ -124,9 +124,7 @@ static void screenPress()
|
|||||||
screen.onPress();
|
screen.onPress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bootEnter() {}
|
||||||
static void bootEnter() {
|
|
||||||
}
|
|
||||||
|
|
||||||
State stateSDS(sdsEnter, NULL, NULL, "SDS");
|
State stateSDS(sdsEnter, NULL, NULL, "SDS");
|
||||||
State stateLS(lsEnter, lsIdle, lsExit, "LS");
|
State stateLS(lsEnter, lsIdle, lsExit, "LS");
|
||||||
@ -138,8 +136,7 @@ Fsm powerFSM(&stateBOOT);
|
|||||||
|
|
||||||
void PowerFSM_setup()
|
void PowerFSM_setup()
|
||||||
{
|
{
|
||||||
powerFSM.add_timed_transition(&stateBOOT, &stateON, 3 * 1000, NULL,
|
powerFSM.add_timed_transition(&stateBOOT, &stateON, 3 * 1000, NULL, "boot timeout");
|
||||||
"boot timeout");
|
|
||||||
|
|
||||||
powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, wakeForPing, "Wake timer");
|
powerFSM.add_transition(&stateLS, &stateDARK, EVENT_WAKE_TIMER, wakeForPing, "Wake timer");
|
||||||
|
|
||||||
|
@ -10,8 +10,7 @@
|
|||||||
* A wrapper for freertos queues. Note: each element object should be small
|
* A wrapper for freertos queues. Note: each element object should be small
|
||||||
* and POD (Plain Old Data type) as elements are memcpied by value.
|
* and POD (Plain Old Data type) as elements are memcpied by value.
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T> class TypedQueue
|
||||||
class TypedQueue
|
|
||||||
{
|
{
|
||||||
static_assert(std::is_pod<T>::value, "T must be pod");
|
static_assert(std::is_pod<T>::value, "T must be pod");
|
||||||
QueueHandle_t h;
|
QueueHandle_t h;
|
||||||
@ -23,38 +22,17 @@ class TypedQueue
|
|||||||
assert(h);
|
assert(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
~TypedQueue()
|
~TypedQueue() { vQueueDelete(h); }
|
||||||
{
|
|
||||||
vQueueDelete(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
int numFree()
|
int numFree() { return uxQueueSpacesAvailable(h); }
|
||||||
{
|
|
||||||
return uxQueueSpacesAvailable(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isEmpty()
|
bool isEmpty() { return uxQueueMessagesWaiting(h) == 0; }
|
||||||
{
|
|
||||||
return uxQueueMessagesWaiting(h) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool enqueue(T x, TickType_t maxWait = portMAX_DELAY)
|
bool enqueue(T x, TickType_t maxWait = portMAX_DELAY) { return xQueueSendToBack(h, &x, maxWait) == pdTRUE; }
|
||||||
{
|
|
||||||
return xQueueSendToBack(h, &x, maxWait) == pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool enqueueFromISR(T x, BaseType_t *higherPriWoken)
|
bool enqueueFromISR(T x, BaseType_t *higherPriWoken) { return xQueueSendToBackFromISR(h, &x, higherPriWoken) == pdTRUE; }
|
||||||
{
|
|
||||||
return xQueueSendToBackFromISR(h, &x, higherPriWoken) == pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dequeue(T *p, TickType_t maxWait = portMAX_DELAY)
|
bool dequeue(T *p, TickType_t maxWait = portMAX_DELAY) { return xQueueReceive(h, p, maxWait) == pdTRUE; }
|
||||||
{
|
|
||||||
return xQueueReceive(h, p, maxWait) == pdTRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dequeueFromISR(T *p, BaseType_t *higherPriWoken)
|
bool dequeueFromISR(T *p, BaseType_t *higherPriWoken) { return xQueueReceiveFromISR(h, p, higherPriWoken); }
|
||||||
{
|
|
||||||
return xQueueReceiveFromISR(h, p, higherPriWoken);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@ -41,10 +41,11 @@ 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
|
// 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)
|
#if !defined(T_BEAM_V10) && !defined(HELTEC_LORA32)
|
||||||
// #define T_BEAM_V10 // AKA Rev1 (second board released)
|
#define T_BEAM_V10 // AKA Rev1 (second board released)
|
||||||
#define HELTEC_LORA32
|
// #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
|
#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
|
#endif
|
||||||
|
|
||||||
// If we are using the JTAG port for debugging, some pins must be left free for that (and things like GPS have to be disabled)
|
// If we are using the JTAG port for debugging, some pins must be left free for that (and things like GPS have to be disabled)
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
#define SATELLITE_IMAGE_WIDTH 16
|
#define SATELLITE_IMAGE_WIDTH 16
|
||||||
#define SATELLITE_IMAGE_HEIGHT 15
|
#define SATELLITE_IMAGE_HEIGHT 15
|
||||||
const uint8_t SATELLITE_IMAGE[] PROGMEM = {
|
const uint8_t SATELLITE_IMAGE[] PROGMEM = {0x00, 0x08, 0x00, 0x1C, 0x00, 0x0E, 0x20, 0x07, 0x70, 0x02,
|
||||||
0x00, 0x08, 0x00, 0x1C, 0x00, 0x0E, 0x20, 0x07, 0x70, 0x02, 0xF8, 0x00,
|
0xF8, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC8, 0x01, 0x9C, 0x54,
|
||||||
0xF0, 0x01, 0xE0, 0x03, 0xC8, 0x01, 0x9C, 0x54, 0x0E, 0x52, 0x07, 0x48,
|
0x0E, 0x52, 0x07, 0x48, 0x02, 0x26, 0x00, 0x10, 0x00, 0x0E};
|
||||||
0x02, 0x26, 0x00, 0x10, 0x00, 0x0E
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
#include "icon.xbm"
|
#include "icon.xbm"
|
||||||
|
107
src/main.cpp
107
src/main.cpp
@ -21,22 +21,22 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "rom/rtc.h"
|
|
||||||
#include <driver/rtc_io.h>
|
|
||||||
#include <Wire.h>
|
|
||||||
#include "BluetoothUtil.h"
|
#include "BluetoothUtil.h"
|
||||||
#include "MeshBluetoothService.h"
|
|
||||||
#include "MeshService.h"
|
|
||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
#include "screen.h"
|
#include "MeshBluetoothService.h"
|
||||||
|
#include "MeshRadio.h"
|
||||||
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "Periodic.h"
|
#include "Periodic.h"
|
||||||
|
#include "PowerFSM.h"
|
||||||
|
#include "configuration.h"
|
||||||
#include "esp32/pm.h"
|
#include "esp32/pm.h"
|
||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
#include "MeshRadio.h"
|
#include "rom/rtc.h"
|
||||||
|
#include "screen.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
#include "PowerFSM.h"
|
#include <Wire.h>
|
||||||
|
#include <driver/rtc_io.h>
|
||||||
|
|
||||||
#ifdef T_BEAM_V10
|
#ifdef T_BEAM_V10
|
||||||
#include "axp20x.h"
|
#include "axp20x.h"
|
||||||
@ -69,31 +69,25 @@ void scanI2Cdevice(void)
|
|||||||
{
|
{
|
||||||
byte err, addr;
|
byte err, addr;
|
||||||
int nDevices = 0;
|
int nDevices = 0;
|
||||||
for (addr = 1; addr < 127; addr++)
|
for (addr = 1; addr < 127; addr++) {
|
||||||
{
|
|
||||||
Wire.beginTransmission(addr);
|
Wire.beginTransmission(addr);
|
||||||
err = Wire.endTransmission();
|
err = Wire.endTransmission();
|
||||||
if (err == 0)
|
if (err == 0) {
|
||||||
{
|
|
||||||
DEBUG_MSG("I2C device found at address 0x%x\n", addr);
|
DEBUG_MSG("I2C device found at address 0x%x\n", addr);
|
||||||
|
|
||||||
nDevices++;
|
nDevices++;
|
||||||
|
|
||||||
if (addr == SSD1306_ADDRESS)
|
if (addr == SSD1306_ADDRESS) {
|
||||||
{
|
|
||||||
ssd1306_found = true;
|
ssd1306_found = true;
|
||||||
DEBUG_MSG("ssd1306 display found\n");
|
DEBUG_MSG("ssd1306 display found\n");
|
||||||
}
|
}
|
||||||
#ifdef T_BEAM_V10
|
#ifdef T_BEAM_V10
|
||||||
if (addr == AXP192_SLAVE_ADDRESS)
|
if (addr == AXP192_SLAVE_ADDRESS) {
|
||||||
{
|
|
||||||
axp192_found = true;
|
axp192_found = true;
|
||||||
DEBUG_MSG("axp192 PMU found\n");
|
DEBUG_MSG("axp192 PMU found\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
} else if (err == 4) {
|
||||||
else if (err == 4)
|
|
||||||
{
|
|
||||||
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
|
DEBUG_MSG("Unknow error at address 0x%x\n", addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,20 +101,16 @@ void scanI2Cdevice(void)
|
|||||||
* Init the power manager chip
|
* Init the power manager chip
|
||||||
*
|
*
|
||||||
* axp192 power
|
* axp192 power
|
||||||
DCDC1 0.7-3.5V @ 1200mA max -> OLED // If you turn this off you'll lose comms to the axp192 because the OLED and the axp192 share the same i2c bus, instead use ssd1306 sleep mode
|
DCDC1 0.7-3.5V @ 1200mA max -> OLED // If you turn this off you'll lose comms to the axp192 because the OLED and the axp192
|
||||||
DCDC2 -> unused
|
share the same i2c bus, instead use ssd1306 sleep mode DCDC2 -> unused DCDC3 0.7-3.5V @ 700mA max -> ESP32 (keep this on!) LDO1
|
||||||
DCDC3 0.7-3.5V @ 700mA max -> ESP32 (keep this on!)
|
30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can
|
||||||
LDO1 30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can not be turned off
|
not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
|
||||||
LDO2 200mA -> LORA
|
|
||||||
LDO3 200mA -> GPS
|
|
||||||
*/
|
*/
|
||||||
void axp192Init()
|
void axp192Init()
|
||||||
{
|
{
|
||||||
#ifdef T_BEAM_V10
|
#ifdef T_BEAM_V10
|
||||||
if (axp192_found)
|
if (axp192_found) {
|
||||||
{
|
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
|
||||||
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS))
|
|
||||||
{
|
|
||||||
DEBUG_MSG("AXP192 Begin PASS\n");
|
DEBUG_MSG("AXP192 Begin PASS\n");
|
||||||
|
|
||||||
// axp.setChgLEDMode(LED_BLINK_4HZ);
|
// axp.setChgLEDMode(LED_BLINK_4HZ);
|
||||||
@ -169,26 +159,21 @@ void axp192Init()
|
|||||||
|
|
||||||
#ifdef PMU_IRQ
|
#ifdef PMU_IRQ
|
||||||
pinMode(PMU_IRQ, INPUT_PULLUP);
|
pinMode(PMU_IRQ, INPUT_PULLUP);
|
||||||
attachInterrupt(PMU_IRQ, [] {
|
attachInterrupt(
|
||||||
pmu_irq = true;
|
PMU_IRQ, [] { pmu_irq = true; }, RISING);
|
||||||
},
|
|
||||||
RISING);
|
|
||||||
|
|
||||||
axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1);
|
axp.adc1Enable(AXP202_BATT_CUR_ADC1, 1);
|
||||||
axp.enableIRQ(AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ, 1);
|
axp.enableIRQ(AXP202_VBUS_REMOVED_IRQ | AXP202_VBUS_CONNECT_IRQ | AXP202_BATT_REMOVED_IRQ | AXP202_BATT_CONNECT_IRQ,
|
||||||
|
1);
|
||||||
axp.clearIRQ();
|
axp.clearIRQ();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
isCharging = axp.isChargeing() ? 1 : 0;
|
isCharging = axp.isChargeing() ? 1 : 0;
|
||||||
isUSBPowered = axp.isVBUSPlug() ? 1 : 0;
|
isUSBPowered = axp.isVBUSPlug() ? 1 : 0;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_MSG("AXP192 Begin FAIL\n");
|
DEBUG_MSG("AXP192 Begin FAIL\n");
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG_MSG("AXP192 not found\n");
|
DEBUG_MSG("AXP192 not found\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -279,8 +264,8 @@ void initBluetooth()
|
|||||||
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
|
powerFSM.trigger(EVENT_BLUETOOTH_PAIR);
|
||||||
screen.startBluetoothPinScreen(pin);
|
screen.startBluetoothPinScreen(pin);
|
||||||
},
|
},
|
||||||
[]() { screen.stopBluetoothPinScreen(); },
|
[]() { screen.stopBluetoothPinScreen(); }, getDeviceName(), HW_VENDOR, xstr(APP_VERSION),
|
||||||
getDeviceName(), HW_VENDOR, xstr(APP_VERSION), xstr(HW_VERSION)); // FIXME, use a real name based on the macaddr
|
xstr(HW_VERSION)); // FIXME, use a real name based on the macaddr
|
||||||
createMeshBluetoothService(serve);
|
createMeshBluetoothService(serve);
|
||||||
|
|
||||||
// Start advertising - this must be done _after_ creating all services
|
// Start advertising - this must be done _after_ creating all services
|
||||||
@ -289,19 +274,15 @@ void initBluetooth()
|
|||||||
|
|
||||||
void setBluetoothEnable(bool on)
|
void setBluetoothEnable(bool on)
|
||||||
{
|
{
|
||||||
if (on != bluetoothOn)
|
if (on != bluetoothOn) {
|
||||||
{
|
|
||||||
DEBUG_MSG("Setting bluetooth enable=%d\n", on);
|
DEBUG_MSG("Setting bluetooth enable=%d\n", on);
|
||||||
|
|
||||||
bluetoothOn = on;
|
bluetoothOn = on;
|
||||||
if (on)
|
if (on) {
|
||||||
{
|
|
||||||
Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap());
|
Serial.printf("Pre BT: %u heap size\n", ESP.getFreeHeap());
|
||||||
// ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
|
// ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
|
||||||
initBluetooth();
|
initBluetooth();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// We have to totally teardown our bluetooth objects to prevent leaks
|
// We have to totally teardown our bluetooth objects to prevent leaks
|
||||||
stopMeshBluetoothService(); // Must do before shutting down bluetooth
|
stopMeshBluetoothService(); // Must do before shutting down bluetooth
|
||||||
deinitBLE();
|
deinitBLE();
|
||||||
@ -360,11 +341,9 @@ void loop()
|
|||||||
// service.radio.rf95.canSleep();
|
// service.radio.rf95.canSleep();
|
||||||
|
|
||||||
#ifdef T_BEAM_V10
|
#ifdef T_BEAM_V10
|
||||||
if (axp192_found)
|
if (axp192_found) {
|
||||||
{
|
|
||||||
#ifdef PMU_IRQ
|
#ifdef PMU_IRQ
|
||||||
if (pmu_irq)
|
if (pmu_irq) {
|
||||||
{
|
|
||||||
pmu_irq = false;
|
pmu_irq = false;
|
||||||
axp.readIRQ();
|
axp.readIRQ();
|
||||||
|
|
||||||
@ -384,14 +363,12 @@ void loop()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef BUTTON_PIN
|
#ifdef BUTTON_PIN
|
||||||
// if user presses button for more than 3 secs, discard our network prefs and reboot (FIXME, use a debounce lib instead of this boilerplate)
|
// if user presses button for more than 3 secs, discard our network prefs and reboot (FIXME, use a debounce lib instead of
|
||||||
|
// this boilerplate)
|
||||||
static bool wasPressed = false;
|
static bool wasPressed = false;
|
||||||
|
|
||||||
|
if (!digitalRead(BUTTON_PIN)) {
|
||||||
if (!digitalRead(BUTTON_PIN))
|
if (!wasPressed) { // just started a new press
|
||||||
{
|
|
||||||
if (!wasPressed)
|
|
||||||
{ // just started a new press
|
|
||||||
DEBUG_MSG("pressing\n");
|
DEBUG_MSG("pressing\n");
|
||||||
|
|
||||||
// doLightSleep();
|
// doLightSleep();
|
||||||
@ -400,9 +377,7 @@ void loop()
|
|||||||
|
|
||||||
powerFSM.trigger(EVENT_PRESS);
|
powerFSM.trigger(EVENT_PRESS);
|
||||||
}
|
}
|
||||||
}
|
} else if (wasPressed) {
|
||||||
else if (wasPressed)
|
|
||||||
{
|
|
||||||
// we just did a release
|
// we just did a release
|
||||||
wasPressed = false;
|
wasPressed = false;
|
||||||
}
|
}
|
||||||
@ -410,8 +385,7 @@ void loop()
|
|||||||
|
|
||||||
// Show boot screen for first 3 seconds, then switch to normal operation.
|
// Show boot screen for first 3 seconds, then switch to normal operation.
|
||||||
static bool showingBootScreen = true;
|
static bool showingBootScreen = true;
|
||||||
if (showingBootScreen && (millis() > 3000))
|
if (showingBootScreen && (millis() > 3000)) {
|
||||||
{
|
|
||||||
screen.stopBootScreen();
|
screen.stopBootScreen();
|
||||||
showingBootScreen = false;
|
showingBootScreen = false;
|
||||||
}
|
}
|
||||||
@ -420,7 +394,8 @@ void loop()
|
|||||||
// i.e. don't just keep spinning in loop as fast as we can.
|
// i.e. don't just keep spinning in loop as fast as we can.
|
||||||
// DEBUG_MSG("msecs %d\n", msecstosleep);
|
// DEBUG_MSG("msecs %d\n", msecstosleep);
|
||||||
|
|
||||||
// FIXME - until button press handling is done by interrupt (see polling above) we can't sleep very long at all or buttons feel slow
|
// FIXME - until button press handling is done by interrupt (see polling above) we can't sleep very long at all or buttons
|
||||||
|
// feel slow
|
||||||
msecstosleep = 10;
|
msecstosleep = 10;
|
||||||
|
|
||||||
delay(msecstosleep);
|
delay(msecstosleep);
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#include <Arduino.h>
|
|
||||||
#include "configuration.h"
|
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include <pb_encode.h>
|
|
||||||
#include <pb_decode.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <pb_decode.h>
|
||||||
|
#include <pb_encode.h>
|
||||||
|
|
||||||
/// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic
|
/// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic
|
||||||
/// returns the encoded packet size
|
/// returns the encoded packet size
|
||||||
@ -12,42 +12,33 @@ size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc
|
|||||||
{
|
{
|
||||||
|
|
||||||
pb_ostream_t stream = pb_ostream_from_buffer(destbuf, destbufsize);
|
pb_ostream_t stream = pb_ostream_from_buffer(destbuf, destbufsize);
|
||||||
if (!pb_encode(&stream, fields, src_struct))
|
if (!pb_encode(&stream, fields, src_struct)) {
|
||||||
{
|
|
||||||
DEBUG_MSG("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream));
|
DEBUG_MSG("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream));
|
||||||
assert(0); // FIXME - panic
|
assert(0); // FIXME - panic
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return stream.bytes_written;
|
return stream.bytes_written;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// helper function for decoding a record as a protobuf, we will return false if the decoding failed
|
/// helper function for decoding a record as a protobuf, we will return false if the decoding failed
|
||||||
bool pb_decode_from_bytes(const uint8_t *srcbuf, size_t srcbufsize, const pb_msgdesc_t *fields, void *dest_struct)
|
bool pb_decode_from_bytes(const uint8_t *srcbuf, size_t srcbufsize, const pb_msgdesc_t *fields, void *dest_struct)
|
||||||
{
|
{
|
||||||
pb_istream_t stream = pb_istream_from_buffer(srcbuf, srcbufsize);
|
pb_istream_t stream = pb_istream_from_buffer(srcbuf, srcbufsize);
|
||||||
if (!pb_decode(&stream, fields, dest_struct))
|
if (!pb_decode(&stream, fields, dest_struct)) {
|
||||||
{
|
|
||||||
DEBUG_MSG("Error: can't decode protobuf %s, pb_msgdesc 0x%p\n", PB_GET_ERROR(&stream), fields);
|
DEBUG_MSG("Error: can't decode protobuf %s, pb_msgdesc 0x%p\n", PB_GET_ERROR(&stream), fields);
|
||||||
return false;
|
return false;
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Read from an Arduino File
|
/// Read from an Arduino File
|
||||||
bool readcb(pb_istream_t *stream, uint8_t *buf, size_t count)
|
bool readcb(pb_istream_t *stream, uint8_t *buf, size_t count)
|
||||||
{
|
{
|
||||||
File *file = (File *)stream->state;
|
File *file = (File *)stream->state;
|
||||||
bool status;
|
bool status;
|
||||||
|
|
||||||
if (buf == NULL)
|
if (buf == NULL) {
|
||||||
{
|
|
||||||
while (count-- && file->read() != EOF)
|
while (count-- && file->read() != EOF)
|
||||||
;
|
;
|
||||||
return count == 0;
|
return count == 0;
|
||||||
@ -61,7 +52,6 @@ bool readcb(pb_istream_t *stream, uint8_t *buf, size_t count)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Write to an arduino file
|
/// Write to an arduino file
|
||||||
bool writecb(pb_ostream_t *stream, const uint8_t *buf, size_t count)
|
bool writecb(pb_ostream_t *stream, const uint8_t *buf, size_t count)
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
/// max number of nodes allowed in the mesh
|
/// max number of nodes allowed in the mesh
|
||||||
#define MAX_NUM_NODES (member_size(DeviceState, node_db) / member_size(DeviceState, node_db[0]))
|
#define MAX_NUM_NODES (member_size(DeviceState, node_db) / member_size(DeviceState, node_db[0]))
|
||||||
|
|
||||||
|
|
||||||
/// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic
|
/// helper function for encoding a record as a protobuf, any failures to encode are fatal and we will panic
|
||||||
/// returns the encoded packet size
|
/// returns the encoded packet size
|
||||||
size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc_t *fields, const void *src_struct);
|
size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc_t *fields, const void *src_struct);
|
||||||
|
@ -96,8 +96,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
|
|||||||
|
|
||||||
// the max length of this buffer is much longer than we can possibly print
|
// the max length of this buffer is much longer than we can possibly print
|
||||||
static char tempBuf[96];
|
static char tempBuf[96];
|
||||||
snprintf(tempBuf, sizeof(tempBuf), " %s",
|
snprintf(tempBuf, sizeof(tempBuf), " %s", mp.payload.variant.data.payload.bytes);
|
||||||
mp.payload.variant.data.payload.bytes);
|
|
||||||
|
|
||||||
display->drawStringMaxWidth(4 + x, 10 + y, 128, tempBuf);
|
display->drawStringMaxWidth(4 + x, 10 + y, 128, tempBuf);
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
#include "configuration.h"
|
#include "sleep.h"
|
||||||
#include "rom/rtc.h"
|
|
||||||
#include <driver/rtc_io.h>
|
|
||||||
#include <Wire.h>
|
|
||||||
#include "BluetoothUtil.h"
|
#include "BluetoothUtil.h"
|
||||||
#include "MeshBluetoothService.h"
|
|
||||||
#include "MeshService.h"
|
|
||||||
#include "GPS.h"
|
#include "GPS.h"
|
||||||
|
#include "MeshBluetoothService.h"
|
||||||
|
#include "MeshRadio.h"
|
||||||
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "Periodic.h"
|
#include "Periodic.h"
|
||||||
|
#include "configuration.h"
|
||||||
#include "esp32/pm.h"
|
#include "esp32/pm.h"
|
||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
#include "MeshRadio.h"
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "sleep.h"
|
#include "rom/rtc.h"
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <driver/rtc_io.h>
|
||||||
|
|
||||||
#ifdef T_BEAM_V10
|
#ifdef T_BEAM_V10
|
||||||
#include "axp20x.h"
|
#include "axp20x.h"
|
||||||
@ -49,8 +49,7 @@ void setLed(bool ledOn)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef T_BEAM_V10
|
#ifdef T_BEAM_V10
|
||||||
if (axp192_found)
|
if (axp192_found) {
|
||||||
{
|
|
||||||
// blink the axp led
|
// blink the axp led
|
||||||
axp.setChgLEDMode(ledOn ? AXP20X_LED_LOW_LEVEL : AXP20X_LED_OFF);
|
axp.setChgLEDMode(ledOn ? AXP20X_LED_LOW_LEVEL : AXP20X_LED_OFF);
|
||||||
}
|
}
|
||||||
@ -76,8 +75,8 @@ void initDeepSleep()
|
|||||||
Not using yet because we are using wake on all buttons being low
|
Not using yet because we are using wake on all buttons being low
|
||||||
|
|
||||||
wakeButtons = esp_sleep_get_ext1_wakeup_status(); // If one of these buttons is set it was the reason we woke
|
wakeButtons = esp_sleep_get_ext1_wakeup_status(); // If one of these buttons is set it was the reason we woke
|
||||||
if (wakeCause == ESP_SLEEP_WAKEUP_EXT1 && !wakeButtons) // we must have been using the 'all buttons rule for waking' to support busted boards, assume button one was pressed
|
if (wakeCause == ESP_SLEEP_WAKEUP_EXT1 && !wakeButtons) // we must have been using the 'all buttons rule for waking' to
|
||||||
wakeButtons = ((uint64_t)1) << buttons.gpios[0];
|
support busted boards, assume button one was pressed wakeButtons = ((uint64_t)1) << buttons.gpios[0];
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// If we booted because our timer ran out or the user pressed reset, send those as fake events
|
// If we booted because our timer ran out or the user pressed reset, send those as fake events
|
||||||
@ -126,8 +125,7 @@ void doDeepSleep(uint64_t msecToWake)
|
|||||||
setLed(false);
|
setLed(false);
|
||||||
|
|
||||||
#ifdef T_BEAM_V10
|
#ifdef T_BEAM_V10
|
||||||
if (axp192_found)
|
if (axp192_found) {
|
||||||
{
|
|
||||||
// No need to turn this off if the power draw in sleep mode really is just 0.2uA and turning it off would
|
// No need to turn this off if the power draw in sleep mode really is just 0.2uA and turning it off would
|
||||||
// leave floating input for the IRQ line
|
// leave floating input for the IRQ line
|
||||||
|
|
||||||
@ -157,10 +155,18 @@ void doDeepSleep(uint64_t msecToWake)
|
|||||||
static const uint8_t rtcGpios[] = {/* 0, */ 2,
|
static const uint8_t rtcGpios[] = {/* 0, */ 2,
|
||||||
/* 4, */
|
/* 4, */
|
||||||
#ifndef USE_JTAG
|
#ifndef USE_JTAG
|
||||||
12, 13, /* 14, */ /* 15, */
|
12,
|
||||||
|
13,
|
||||||
|
/* 14, */ /* 15, */
|
||||||
#endif
|
#endif
|
||||||
/* 25, */ 26, /* 27, */
|
/* 25, */ 26, /* 27, */
|
||||||
32, 33, 34, 35, 36, 37, /* 38, */ 39};
|
32,
|
||||||
|
33,
|
||||||
|
34,
|
||||||
|
35,
|
||||||
|
36,
|
||||||
|
37,
|
||||||
|
/* 38, */ 39};
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(rtcGpios); i++)
|
for (int i = 0; i < sizeof(rtcGpios); i++)
|
||||||
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
|
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
|
||||||
@ -180,8 +186,8 @@ void doDeepSleep(uint64_t msecToWake)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Not needed because both of the current boards have external pullups
|
// 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)
|
// FIXME change polarity in hw so we can wake on ANY_HIGH instead - that would allow us to use all three buttons (instead of
|
||||||
// gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
// just the first) gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
||||||
|
|
||||||
esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ALL_LOW);
|
esp_sleep_enable_ext1_wakeup(gpioMask, ESP_EXT1_WAKEUP_ALL_LOW);
|
||||||
#endif
|
#endif
|
||||||
@ -221,7 +227,8 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
|
|||||||
assert(esp_sleep_enable_gpio_wakeup() == ESP_OK);
|
assert(esp_sleep_enable_gpio_wakeup() == ESP_OK);
|
||||||
assert(esp_sleep_enable_timer_wakeup(sleepUsec) == ESP_OK);
|
assert(esp_sleep_enable_timer_wakeup(sleepUsec) == ESP_OK);
|
||||||
assert(esp_light_sleep_start() == ESP_OK);
|
assert(esp_light_sleep_start() == ESP_OK);
|
||||||
//DEBUG_MSG("Exit light sleep b=%d, rf95=%d, pmu=%d\n", digitalRead(BUTTON_PIN), digitalRead(DIO0_GPIO), digitalRead(PMU_IRQ));
|
// 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();
|
return esp_sleep_get_wakeup_cause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user