mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-25 22:20:27 +00:00
Merge pull request #2739 from meshtastic/delivery-report
UI/UX: Display delivered message on incoming ACK.
This commit is contained in:
commit
35938392f1
@ -73,58 +73,3 @@ template <class T> class MemoryDynamic : public Allocator<T>
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A pool based allocator
|
||||
*
|
||||
*/
|
||||
template <class T> class MemoryPool : public Allocator<T>
|
||||
{
|
||||
PointerQueue<T> dead;
|
||||
|
||||
T *buf; // our large raw block of memory
|
||||
|
||||
size_t maxElements;
|
||||
|
||||
public:
|
||||
explicit MemoryPool(size_t _maxElements) : dead(_maxElements), maxElements(_maxElements)
|
||||
{
|
||||
buf = new T[maxElements];
|
||||
|
||||
// prefill dead
|
||||
for (size_t i = 0; i < maxElements; i++)
|
||||
release(&buf[i]);
|
||||
}
|
||||
|
||||
~MemoryPool() { delete[] buf; }
|
||||
|
||||
/// Return a buffer for use by others
|
||||
void release(T *p)
|
||||
{
|
||||
assert(p >= buf &&
|
||||
(size_t)(p - buf) <
|
||||
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||
assert(dead.enqueue(p, 0));
|
||||
}
|
||||
|
||||
#ifdef HAS_FREE_RTOS
|
||||
/// 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)
|
||||
{
|
||||
assert(p >= buf &&
|
||||
(size_t)(p - buf) <
|
||||
maxElements); // sanity check to make sure a programmer didn't free something that didn't come from this pool
|
||||
assert(dead.enqueueFromISR(p, higherPriWoken));
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/// Return a queable object which has been prefilled with zeros - allow timeout to wait for available buffers (you
|
||||
/// probably don't want this version).
|
||||
virtual T *alloc(TickType_t maxWait)
|
||||
{
|
||||
T *p = dead.dequeuePtr(maxWait);
|
||||
assert(p);
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
@ -140,6 +140,22 @@ void MeshService::reloadOwner(bool shouldSave)
|
||||
}
|
||||
}
|
||||
|
||||
// search the queue for a request id and return the matching nodenum
|
||||
NodeNum MeshService::getNodenumFromRequestId(uint32_t request_id)
|
||||
{
|
||||
NodeNum nodenum = 0;
|
||||
for (int i = 0; i < toPhoneQueue.numUsed(); i++) {
|
||||
meshtastic_MeshPacket *p = toPhoneQueue.dequeuePtr(0);
|
||||
if (p->id == request_id) {
|
||||
nodenum = p->to;
|
||||
// make sure to continue this to make one full loop
|
||||
}
|
||||
// put it right back on the queue
|
||||
toPhoneQueue.enqueue(p, 0);
|
||||
}
|
||||
return nodenum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh)
|
||||
* Called by PhoneAPI.handleToRadio. Note: p is a scratch buffer, this function is allowed to write to it but it can not keep a
|
||||
|
@ -82,6 +82,9 @@ class MeshService
|
||||
/// Return the next MqttClientProxyMessage packet destined to the phone.
|
||||
meshtastic_MqttClientProxyMessage *getMqttClientProxyMessageForPhone() { return toPhoneMqttProxyQueue.dequeuePtr(0); }
|
||||
|
||||
// search the queue for a request id and return the matching nodenum
|
||||
NodeNum getNodenumFromRequestId(uint32_t request_id);
|
||||
|
||||
// Release QueueStatus packet to pool
|
||||
void releaseQueueStatusToPool(meshtastic_QueueStatus *p) { queueStatusPool.release(p); }
|
||||
|
||||
|
@ -27,6 +27,8 @@ template <class T> class TypedQueue
|
||||
|
||||
bool isEmpty() { return uxQueueMessagesWaiting(h) == 0; }
|
||||
|
||||
int numUsed() { return uxQueueMessagesWaiting(h); }
|
||||
|
||||
/** euqueue a packet. Also, maxWait used to default to portMAX_DELAY, but we now want to callers to THINK about what blocking
|
||||
* they want */
|
||||
bool enqueue(T x, TickType_t maxWait)
|
||||
@ -80,6 +82,8 @@ template <class T> class TypedQueue
|
||||
|
||||
bool isEmpty() { return q.empty(); }
|
||||
|
||||
int numUsed() { return q.size(); }
|
||||
|
||||
bool enqueue(T x, TickType_t maxWait = portMAX_DELAY)
|
||||
{
|
||||
if (reader) {
|
||||
|
@ -233,7 +233,9 @@ void CannedMessageModule::sendText(NodeNum dest, const char *message, bool wantR
|
||||
|
||||
LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes);
|
||||
|
||||
service.sendToMesh(p);
|
||||
service.sendToMesh(
|
||||
p, RX_SRC_LOCAL,
|
||||
true); // send to mesh, cc to phone. Even if there's no phone connected, this stores the message to match ACKs
|
||||
}
|
||||
|
||||
int32_t CannedMessageModule::runOnce()
|
||||
@ -244,7 +246,8 @@ int32_t CannedMessageModule::runOnce()
|
||||
}
|
||||
// LOG_DEBUG("Check status\n");
|
||||
UIFrameEvent e = {false, true};
|
||||
if (this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
|
||||
if ((this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) ||
|
||||
(this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED)) {
|
||||
// TODO: might have some feedback of sendig state
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
|
||||
e.frameChanged = true;
|
||||
@ -483,7 +486,18 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
{
|
||||
char buffer[50];
|
||||
|
||||
if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
|
||||
if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) {
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
String displayString;
|
||||
if (this->ack) {
|
||||
displayString = "Delivered to\n%s";
|
||||
} else {
|
||||
displayString = "Delivery failed\nto %s";
|
||||
}
|
||||
display->drawStringf(display->getWidth() / 2 + x, 0 + y + 12, buffer, displayString,
|
||||
cannedMessageModule->getNodeName(this->incoming));
|
||||
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) {
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(display->getWidth() / 2 + x, 0 + y + 12, "Sending...");
|
||||
@ -546,6 +560,27 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
}
|
||||
}
|
||||
|
||||
ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP) {
|
||||
// look for a request_id
|
||||
if (mp.decoded.request_id != 0) {
|
||||
UIFrameEvent e = {false, true};
|
||||
e.frameChanged = true;
|
||||
this->runState = CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED;
|
||||
this->incoming = service.getNodenumFromRequestId(mp.decoded.request_id);
|
||||
meshtastic_Routing decoded = meshtastic_Routing_init_default;
|
||||
pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_Routing_fields, &decoded);
|
||||
this->ack = decoded.error_reason == meshtastic_Routing_Error_NONE;
|
||||
this->notifyObservers(&e);
|
||||
// run the next time 2 seconds later
|
||||
setIntervalFromNow(2000);
|
||||
}
|
||||
}
|
||||
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
|
||||
void CannedMessageModule::loadProtoForModule()
|
||||
{
|
||||
if (!nodeDB.loadProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size,
|
||||
@ -650,4 +685,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
@ -9,6 +9,7 @@ enum cannedMessageModuleRunState {
|
||||
CANNED_MESSAGE_RUN_STATE_ACTIVE,
|
||||
CANNED_MESSAGE_RUN_STATE_FREETEXT,
|
||||
CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE,
|
||||
CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED,
|
||||
CANNED_MESSAGE_RUN_STATE_ACTION_SELECT,
|
||||
CANNED_MESSAGE_RUN_STATE_ACTION_UP,
|
||||
CANNED_MESSAGE_RUN_STATE_ACTION_DOWN,
|
||||
@ -37,15 +38,29 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
const char *getMessageByIndex(int index);
|
||||
const char *getNodeName(NodeNum node);
|
||||
bool shouldDraw();
|
||||
void eventUp();
|
||||
void eventDown();
|
||||
void eventSelect();
|
||||
// void eventUp();
|
||||
// void eventDown();
|
||||
// void eventSelect();
|
||||
|
||||
void handleGetCannedMessageModuleMessages(const meshtastic_MeshPacket &req, meshtastic_AdminMessage *response);
|
||||
void handleSetCannedMessageModuleMessages(const char *from_msg);
|
||||
|
||||
String drawWithCursor(String text, int cursor);
|
||||
|
||||
/*
|
||||
-Override the wantPacket method. We need the Routing Messages to look for ACKs.
|
||||
*/
|
||||
virtual bool wantPacket(const meshtastic_MeshPacket *p) override
|
||||
{
|
||||
switch (p->decoded.portnum) {
|
||||
case meshtastic_PortNum_TEXT_MESSAGE_APP:
|
||||
case meshtastic_PortNum_ROUTING_APP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
@ -63,6 +78,12 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
meshtastic_AdminMessage *request,
|
||||
meshtastic_AdminMessage *response) override;
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
* @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered
|
||||
* for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
|
||||
|
||||
void loadProtoForModule();
|
||||
bool saveProtoForModule();
|
||||
|
||||
@ -75,6 +96,8 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
String freetext = ""; // Text Buffer for Freetext Editor
|
||||
bool destSelect = false; // Freetext Editor Mode
|
||||
NodeNum dest = NODENUM_BROADCAST;
|
||||
NodeNum incoming = NODENUM_BROADCAST;
|
||||
bool ack = false; // True means ACK, false means NAK (error_reason != NONE)
|
||||
|
||||
char messageStore[CANNED_MESSAGE_MODULE_MESSAGES_SIZE + 1];
|
||||
char *messages[CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT];
|
||||
@ -83,4 +106,4 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
|
||||
};
|
||||
|
||||
extern CannedMessageModule *cannedMessageModule;
|
||||
#endif
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user