allow TBEAMs to provide approx GPS time to Heltec devices

This commit is contained in:
geeksville 2020-02-26 09:00:53 -08:00
parent cace2f4290
commit 877e312833
5 changed files with 61 additions and 45 deletions

12
TODO.md
View File

@ -3,9 +3,6 @@
Items to complete soon (next couple of alpha releases). Items to complete soon (next couple of alpha releases).
* text messages are not showing on local screen if screen was on * text messages are not showing on local screen if screen was on
* protobufs are sometimes corrupted after sleep!
* stay awake while charging
* check gps battery voltage
* The following three items are all the same: * The following three items are all the same:
Have state machine properly enter deep sleep based on loss of mesh and phone comms. Have state machine properly enter deep sleep based on loss of mesh and phone comms.
@ -17,7 +14,6 @@ for it (because it will redownload the nodedb when it comes back)
being I have it set at 2 minutes to ensure enough time for a GPS lock from scratch. being I have it set at 2 minutes to ensure enough time for a GPS lock from scratch.
* retest BLE software update for both board types * retest BLE software update for both board types
* send note about Adafruit Clue
* report on wikifactory * report on wikifactory
* send note to the guy who designed the cases * send note to the guy who designed the cases
* remeasure wake time power draws now that we run CPU down at 80MHz * remeasure wake time power draws now that we run CPU down at 80MHz
@ -26,6 +22,7 @@ being I have it set at 2 minutes to ensure enough time for a GPS lock from scrat
Items to complete before the first beta release. Items to complete before the first beta release.
* check fcc rules on duty cycle. we might not need to freq hop. https://www.sunfiretesting.com/LoRa-FCC-Certification-Guide/
* use fuse bits to store the board type and region. So one load can be used on all boards * use fuse bits to store the board type and region. So one load can be used on all boards
* "AXP192 interrupt is not firing, remove this temporary polling of battery state" * "AXP192 interrupt is not firing, remove this temporary polling of battery state"
* make mesh aware network timing state machine (sync wake windows to gps time) * make mesh aware network timing state machine (sync wake windows to gps time)
@ -47,7 +44,7 @@ Items to complete before the first beta release.
* make an about to sleep screen * make an about to sleep screen
* don't send location packets if we haven't moved * don't send location packets if we haven't moved
* scrub default radio config settings for bandwidth/range/speed * scrub default radio config settings for bandwidth/range/speed
* add basic crypto - http://rweather.github.io/arduinolibs/crypto.html with speck https://www.airspayce.com/mikem/arduino/RadioHead/rf95_encrypted_client_8pde-example.html * add basic crypto - https://github.com/chegewara/esp32-mbedtls-aes-test/blob/master/main/main.c https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation - use ECB at first (though it is shit) because it doesn't require us to send 16 bytes of IV with each packet. Then OFB per example
* override peekAtMessage so we can see any messages that pass through our node (even if not broadcast)? would that be useful? * override peekAtMessage so we can see any messages that pass through our node (even if not broadcast)? would that be useful?
* sendToMesh can currently block for a long time, instead have it just queue a packet for a radio freertos thread * sendToMesh can currently block for a long time, instead have it just queue a packet for a radio freertos thread
* How do avalanche beacons work? Could this do that as well? possibly by using beacon mode feature of the RF95? * How do avalanche beacons work? Could this do that as well? possibly by using beacon mode feature of the RF95?
@ -65,7 +62,6 @@ During the beta timeframe the following improvements 'would be nice' (and yeah -
* make an install script to let novices install software on their boards * make an install script to let novices install software on their boards
* fix the frequency error reading in the RF95 RX code (can't do floating point math in an ISR ;-) * fix the frequency error reading in the RF95 RX code (can't do floating point math in an ISR ;-)
* See CustomRF95::send and fix the problem of dropping partially received packets if we want to start sending * See CustomRF95::send and fix the problem of dropping partially received packets if we want to start sending
* swap out speck for hw-accelerated full AES https://github.com/espressif/arduino-esp32/blob/master/tools/sdk/include/esp32/hwcrypto/aes.h
* use variable length arduino Strings in protobufs (instead of current fixed buffers) * use variable length arduino Strings in protobufs (instead of current fixed buffers)
* don't even power on bluetooth until we have some data to send to the android phone. Most of the time we should be sleeping in a lowpower "listening for lora" only mode. Once we have some packets for the phone, then power on bluetooth * don't even power on bluetooth until we have some data to send to the android phone. Most of the time we should be sleeping in a lowpower "listening for lora" only mode. Once we have some packets for the phone, then power on bluetooth
until the phone pulls those packets. Ever so often power on bluetooth just so we can see if the phone wants to send some packets. Possibly might need ULP processor to help with this wake process. until the phone pulls those packets. Ever so often power on bluetooth just so we can see if the phone wants to send some packets. Possibly might need ULP processor to help with this wake process.
@ -183,3 +179,7 @@ Items after the first final candidate release.
* have sw update prevent BLE sleep * have sw update prevent BLE sleep
* manually delete characteristics/descs * manually delete characteristics/descs
* leave lora receiver always on * leave lora receiver always on
* protobufs are sometimes corrupted after sleep!
* stay awake while charging
* check gps battery voltage
* if a position report includes ground truth time and we don't have time yet, set our clock from that. It is better than nothing.

View File

@ -33,8 +33,8 @@ public:
void onRead(BLECharacteristic *c) void onRead(BLECharacteristic *c)
{ {
BLEKeepAliveCallbacks::onRead(c); BLEKeepAliveCallbacks::onRead(c);
DEBUG_MSG("Got proto read\n");
size_t numbytes = pb_encode_to_bytes(trBytes, sizeof(trBytes), fields, my_struct); size_t numbytes = pb_encode_to_bytes(trBytes, sizeof(trBytes), fields, my_struct);
DEBUG_MSG("pbread from %s returns %d bytes\n", c->getUUID().toString().c_str(), numbytes);
c->setValue(trBytes, numbytes); c->setValue(trBytes, numbytes);
} }
@ -51,8 +51,8 @@ protected:
bool writeToDest(BLECharacteristic *c, void *dest) bool writeToDest(BLECharacteristic *c, void *dest)
{ {
// dumpCharacteristic(pCharacteristic); // dumpCharacteristic(pCharacteristic);
DEBUG_MSG("Got on proto write\n");
std::string src = c->getValue(); std::string src = c->getValue();
DEBUG_MSG("pbwrite to %s of %d bytes\n", c->getUUID().toString().c_str(), src.length());
return pb_decode_from_bytes((const uint8_t *)src.c_str(), src.length(), fields, dest); return pb_decode_from_bytes((const uint8_t *)src.c_str(), src.length(), fields, dest);
} }
}; };
@ -88,7 +88,7 @@ public:
void onWrite(BLECharacteristic *c) void onWrite(BLECharacteristic *c)
{ {
BLEKeepAliveCallbacks::onWrite(c); BLEKeepAliveCallbacks::onWrite(c);
DEBUG_MSG("Got on nodeinfo write\n"); DEBUG_MSG("Reset nodeinfo read pointer\n");
nodeDB.resetReadPointer(); nodeDB.resetReadPointer();
} }
}; };
@ -188,18 +188,17 @@ public:
} }
else else
{ {
DEBUG_MSG("delivering toPhone packet to phone\n"); static FromRadio fRadio;
static FromRadio fradio;
// Encapsulate as a ToRadio packet // Encapsulate as a ToRadio packet
memset(&fradio, 0, sizeof(fradio)); memset(&fRadio, 0, sizeof(fRadio));
fradio.which_variant = FromRadio_packet_tag; fRadio.which_variant = FromRadio_packet_tag;
fradio.variant.packet = *mp; fRadio.variant.packet = *mp;
service.releaseToPool(mp); // we just copied the bytes, so don't need this buffer anymore service.releaseToPool(mp); // we just copied the bytes, so don't need this buffer anymore
size_t numbytes = pb_encode_to_bytes(trBytes, sizeof(trBytes), FromRadio_fields, &fradio); size_t numbytes = pb_encode_to_bytes(trBytes, sizeof(trBytes), FromRadio_fields, &fRadio);
DEBUG_MSG("delivering toPhone packet to phone %d bytes\n", numbytes);
c->setValue(trBytes, numbytes); c->setValue(trBytes, numbytes);
} }
} }

View File

@ -123,10 +123,33 @@ MeshPacket *MeshService::handleFromRadioUser(MeshPacket *mp)
return mp; return mp;
} }
void MeshService::handleIncomingPosition(MeshPacket *mp)
{
if (mp->has_payload && mp->payload.which_variant == SubPacket_position_tag)
{
DEBUG_MSG("handled incoming position time=%u\n", mp->payload.variant.position.time);
if (mp->payload.variant.position.time)
{
struct timeval tv;
uint32_t secs = mp->payload.variant.position.time;
tv.tv_sec = secs;
tv.tv_usec = 0;
gps.perhapsSetRTC(&tv);
}
}
}
void MeshService::handleFromRadio(MeshPacket *mp) void MeshService::handleFromRadio(MeshPacket *mp)
{ {
mp->rx_time = gps.getValidTime(); // store the arrival timestamp for the phone mp->rx_time = gps.getValidTime(); // store the arrival timestamp for the phone
// If it is a position packet, perhaps set our clock (if we don't have a GPS of our own, otherwise wait for that to work)
if(!myNodeInfo.has_gps)
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);
@ -149,7 +172,7 @@ void MeshService::handleFromRadio(MeshPacket *mp)
} }
assert(toPhoneQueue.enqueue(mp, 0) == pdTRUE); // FIXME, instead of failing for full queue, delete the oldest mssages assert(toPhoneQueue.enqueue(mp, 0) == pdTRUE); // FIXME, instead of failing for full queue, delete the oldest mssages
if(mp->payload.want_response) if (mp->payload.want_response)
sendNetworkPing(mp->from); sendNetworkPing(mp->from);
} }
else else
@ -168,7 +191,6 @@ void MeshService::handleFromRadio()
bluetoothNotifyFromNum(fromNum); bluetoothNotifyFromNum(fromNum);
} }
uint32_t sendOwnerCb() uint32_t sendOwnerCb()
{ {
service.sendOurOwner(); service.sendOurOwner();
@ -209,17 +231,7 @@ void MeshService::handleToRadio(std::string s)
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
if (r.variant.packet.has_payload && r.variant.packet.payload.which_variant == SubPacket_position_tag && r.variant.packet.payload.variant.position.time) handleIncomingPosition(&r.variant.packet); // If it is a position packet, perhaps set our clock
{
struct timeval tv;
uint32_t secs = r.variant.packet.payload.variant.position.time;
// FIXME, this is a shit not right version of the standard def of unix time!!!
tv.tv_sec = secs;
tv.tv_usec = 0;
gps.perhapsSetRTC(&tv);
}
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)
@ -247,8 +259,14 @@ 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 nodes shouldn't trust it anyways)
// Note: for now, we allow a device with a local GPS to include the time, so that gpsless devices can get time.
if (p->has_payload && p->payload.which_variant == SubPacket_position_tag) if (p->has_payload && p->payload.which_variant == SubPacket_position_tag)
{
if (!myNodeInfo.has_gps)
p->payload.variant.position.time = 0; p->payload.variant.position.time = 0;
else
DEBUG_MSG("Providing time to mesh %u\n", p->payload.variant.position.time);
}
// 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())
@ -295,8 +313,7 @@ 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;
// FIXME - for now we are leaving this in the sent packets (for debugging) 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 = 0; // No need to send time, other node won't trust it anyways
sendToMesh(p); sendToMesh(p);
} }

View File

@ -86,6 +86,9 @@ private:
/// handle a user packet that just arrived on the radio, return NULL if we should not process this packet at all /// handle a user packet that just arrived on the radio, return NULL if we should not process this packet at all
MeshPacket *handleFromRadioUser(MeshPacket *mp); MeshPacket *handleFromRadioUser(MeshPacket *mp);
/// look at inbound packets and if they contain a position with time, possibly set our clock
void handleIncomingPosition(MeshPacket *mp);
}; };
extern MeshService service; extern MeshService service;

View File

@ -33,8 +33,8 @@ typedef enum _ChannelSettings_ModemConfig {
typedef enum _DeviceState_Version { typedef enum _DeviceState_Version {
DeviceState_Version_Unset = 0, DeviceState_Version_Unset = 0,
DeviceState_Version_Minimum = 16, DeviceState_Version_Minimum = 17,
DeviceState_Version_Current = 16 DeviceState_Version_Current = 17
} DeviceState_Version; } DeviceState_Version;
/* Struct definitions */ /* Struct definitions */
@ -63,7 +63,6 @@ typedef struct _Position {
double longitude; double longitude;
int32_t altitude; int32_t altitude;
int32_t battery_level; int32_t battery_level;
bool from_hardware;
uint32_t time; uint32_t time;
} Position; } Position;
@ -176,7 +175,7 @@ typedef struct _ToRadio {
/* Initializer values for message structs */ /* Initializer values for message structs */
#define Position_init_default {0, 0, 0, 0, 0, 0} #define Position_init_default {0, 0, 0, 0, 0}
#define Data_init_default {_Data_Type_MIN, {0, {0}}} #define Data_init_default {_Data_Type_MIN, {0, {0}}}
#define User_init_default {"", "", "", {0}} #define User_init_default {"", "", "", {0}}
#define SubPacket_init_default {0, {Position_init_default}, 0} #define SubPacket_init_default {0, {Position_init_default}, 0}
@ -189,7 +188,7 @@ typedef struct _ToRadio {
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default}, _DeviceState_Version_MIN, false, MeshPacket_init_default} #define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default, MeshPacket_init_default}, _DeviceState_Version_MIN, false, MeshPacket_init_default}
#define FromRadio_init_default {0, 0, {MeshPacket_init_default}} #define FromRadio_init_default {0, 0, {MeshPacket_init_default}}
#define ToRadio_init_default {0, {MeshPacket_init_default}} #define ToRadio_init_default {0, {MeshPacket_init_default}}
#define Position_init_zero {0, 0, 0, 0, 0, 0} #define Position_init_zero {0, 0, 0, 0, 0}
#define Data_init_zero {_Data_Type_MIN, {0, {0}}} #define Data_init_zero {_Data_Type_MIN, {0, {0}}}
#define User_init_zero {"", "", "", {0}} #define User_init_zero {"", "", "", {0}}
#define SubPacket_init_zero {0, {Position_init_zero}, 0} #define SubPacket_init_zero {0, {Position_init_zero}, 0}
@ -218,7 +217,6 @@ typedef struct _ToRadio {
#define Position_longitude_tag 2 #define Position_longitude_tag 2
#define Position_altitude_tag 3 #define Position_altitude_tag 3
#define Position_battery_level_tag 4 #define Position_battery_level_tag 4
#define Position_from_hardware_tag 5
#define Position_time_tag 6 #define Position_time_tag 6
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1 #define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
#define RadioConfig_UserPreferences_send_owner_interval_tag 2 #define RadioConfig_UserPreferences_send_owner_interval_tag 2
@ -269,7 +267,6 @@ X(a, STATIC, SINGULAR, DOUBLE, latitude, 1) \
X(a, STATIC, SINGULAR, DOUBLE, longitude, 2) \ X(a, STATIC, SINGULAR, DOUBLE, longitude, 2) \
X(a, STATIC, SINGULAR, INT32, altitude, 3) \ X(a, STATIC, SINGULAR, INT32, altitude, 3) \
X(a, STATIC, SINGULAR, INT32, battery_level, 4) \ X(a, STATIC, SINGULAR, INT32, battery_level, 4) \
X(a, STATIC, SINGULAR, BOOL, from_hardware, 5) \
X(a, STATIC, SINGULAR, UINT32, time, 6) X(a, STATIC, SINGULAR, UINT32, time, 6)
#define Position_CALLBACK NULL #define Position_CALLBACK NULL
#define Position_DEFAULT NULL #define Position_DEFAULT NULL
@ -420,7 +417,7 @@ extern const pb_msgdesc_t ToRadio_msg;
#define ToRadio_fields &ToRadio_msg #define ToRadio_fields &ToRadio_msg
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define Position_size 48 #define Position_size 46
#define Data_size 256 #define Data_size 256
#define User_size 72 #define User_size 72
#define SubPacket_size 261 #define SubPacket_size 261
@ -428,9 +425,9 @@ extern const pb_msgdesc_t ToRadio_msg;
#define ChannelSettings_size 50 #define ChannelSettings_size 50
#define RadioConfig_size 126 #define RadioConfig_size 126
#define RadioConfig_UserPreferences_size 72 #define RadioConfig_UserPreferences_size 72
#define NodeInfo_size 157 #define NodeInfo_size 155
#define MyNodeInfo_size 24 #define MyNodeInfo_size 24
#define DeviceState_size 15085 #define DeviceState_size 15021
#define FromRadio_size 301 #define FromRadio_size 301
#define ToRadio_size 295 #define ToRadio_size 295