mirror of
https://github.com/meshtastic/firmware.git
synced 2025-08-11 16:07:13 +00:00
Fix GPIO service and cleanup response handling
This commit is contained in:
parent
c0cfd0bb41
commit
cec905914c
@ -9,7 +9,7 @@
|
|||||||
; https://docs.platformio.org/page/projectconf.html
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
;default_envs = tbeam
|
default_envs = tbeam
|
||||||
;default_envs = tbeam0.7
|
;default_envs = tbeam0.7
|
||||||
;default_envs = heltec
|
;default_envs = heltec
|
||||||
;default_envs = tlora-v1
|
;default_envs = tlora-v1
|
||||||
@ -18,7 +18,7 @@
|
|||||||
;default_envs = lora-relay-v1 # nrf board
|
;default_envs = lora-relay-v1 # nrf board
|
||||||
;default_envs = eink
|
;default_envs = eink
|
||||||
;default_envs = nrf52840dk-geeksville
|
;default_envs = nrf52840dk-geeksville
|
||||||
default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
|
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
; common is not currently used
|
; common is not currently used
|
||||||
@ -397,4 +397,4 @@ lib_deps =
|
|||||||
;extends = esp32_base
|
;extends = esp32_base
|
||||||
;board = genieblocks_lora
|
;board = genieblocks_lora
|
||||||
;build_flags =
|
;build_flags =
|
||||||
; ${esp32_base.build_flags} -D GENIEBLOCKS
|
; ${esp32_base.build_flags} -D GENIEBLOCKS
|
||||||
|
@ -86,8 +86,10 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
|||||||
/// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious)
|
/// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious)
|
||||||
bool wantsPacket = (isDecoded || pi.encryptedOk) && (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
|
bool wantsPacket = (isDecoded || pi.encryptedOk) && (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
|
||||||
|
|
||||||
|
DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket);
|
||||||
|
assert(!pi.myReply); // If it is !null it means we have a bug, because it should have been sent the previous time
|
||||||
|
|
||||||
if (wantsPacket) {
|
if (wantsPacket) {
|
||||||
// DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket);
|
|
||||||
pluginFound = true;
|
pluginFound = true;
|
||||||
|
|
||||||
/// received channel (or NULL if not decoded)
|
/// received channel (or NULL if not decoded)
|
||||||
@ -124,6 +126,14 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
|||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("Plugin %s considered\n", pi.name);
|
DEBUG_MSG("Plugin %s considered\n", pi.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the requester didn't ask for a response we might need to discard unused replies to prevent memory leaks
|
||||||
|
if (pi.myReply) {
|
||||||
|
DEBUG_MSG("Discarding an unneeded response\n");
|
||||||
|
packetPool.release(pi.myReply);
|
||||||
|
pi.myReply = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (handled) {
|
if (handled) {
|
||||||
DEBUG_MSG("Plugin %s handled and skipped other processing\n", pi.name);
|
DEBUG_MSG("Plugin %s handled and skipped other processing\n", pi.name);
|
||||||
break;
|
break;
|
||||||
@ -136,7 +146,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
|||||||
|
|
||||||
if (mp.decoded.want_response && toUs) {
|
if (mp.decoded.want_response && toUs) {
|
||||||
if (currentReply) {
|
if (currentReply) {
|
||||||
DEBUG_MSG("Sending response\n");
|
printPacket("Sending response", currentReply);
|
||||||
service.sendToMesh(currentReply);
|
service.sendToMesh(currentReply);
|
||||||
currentReply = NULL;
|
currentReply = NULL;
|
||||||
} else {
|
} else {
|
||||||
@ -154,6 +164,13 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
|||||||
DEBUG_MSG("No plugins interested in portnum=%d\n", mp.decoded.portnum);
|
DEBUG_MSG("No plugins interested in portnum=%d\n", mp.decoded.portnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MeshPacket *MeshPlugin::allocReply()
|
||||||
|
{
|
||||||
|
auto r = myReply;
|
||||||
|
myReply = NULL; // Only use each reply once
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
* so that subclasses can (optionally) send a response back to the original sender. Implementing this method
|
* so that subclasses can (optionally) send a response back to the original sender. Implementing this method
|
||||||
* is optional
|
* is optional
|
||||||
@ -176,7 +193,7 @@ void MeshPlugin::sendResponse(const MeshPacket &req)
|
|||||||
void setReplyTo(MeshPacket *p, const MeshPacket &to)
|
void setReplyTo(MeshPacket *p, const MeshPacket &to)
|
||||||
{
|
{
|
||||||
assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now
|
assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now
|
||||||
p->to = getFrom(&to);
|
p->to = getFrom(&to); // Make sure that if we are sending to the local node, we use our local node addr, not 0
|
||||||
p->channel = to.channel; // Use the same channel that the request came in on
|
p->channel = to.channel; // Use the same channel that the request came in on
|
||||||
|
|
||||||
// No need for an ack if we are just delivering locally (it just generates an ignored ack)
|
// No need for an ack if we are just delivering locally (it just generates an ignored ack)
|
||||||
|
@ -69,6 +69,11 @@ class MeshPlugin
|
|||||||
*/
|
*/
|
||||||
static const MeshPacket *currentRequest;
|
static const MeshPacket *currentRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If your handler wants to send a response, simply set currentReply and it will be sent at the end of response handling.
|
||||||
|
*/
|
||||||
|
MeshPacket *myReply = NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize your plugin. This setup function is called once after all hardware and mesh protocol layers have
|
* Initialize your plugin. This setup function is called once after all hardware and mesh protocol layers have
|
||||||
* been initialized
|
* been initialized
|
||||||
@ -87,8 +92,12 @@ class MeshPlugin
|
|||||||
virtual bool handleReceived(const MeshPacket &mp) { return false; }
|
virtual bool handleReceived(const MeshPacket &mp) { return false; }
|
||||||
|
|
||||||
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
* so that subclasses can (optionally) send a response back to the original sender. */
|
* so that subclasses can (optionally) send a response back to the original sender.
|
||||||
virtual MeshPacket *allocReply() { return NULL; }
|
*
|
||||||
|
* Note: most implementers don't need to override this, instead: If while handling a request you have a reply, just set
|
||||||
|
* the protected reply field in this instance.
|
||||||
|
* */
|
||||||
|
virtual MeshPacket *allocReply();
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @return true if you want to be alloced a UI screen frame
|
* @return true if you want to be alloced a UI screen frame
|
||||||
@ -106,6 +115,7 @@ class MeshPlugin
|
|||||||
* the RoutingPlugin to avoid sending redundant acks
|
* the RoutingPlugin to avoid sending redundant acks
|
||||||
*/
|
*/
|
||||||
static MeshPacket *currentReply;
|
static MeshPacket *currentReply;
|
||||||
|
|
||||||
friend class ReliableRouter;
|
friend class ReliableRouter;
|
||||||
|
|
||||||
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
|
@ -19,7 +19,7 @@ void AdminPlugin::handleGetChannel(const MeshPacket &req, uint32_t channelIndex)
|
|||||||
AdminMessage r = AdminMessage_init_default;
|
AdminMessage r = AdminMessage_init_default;
|
||||||
r.get_channel_response = channels.getByIndex(channelIndex);
|
r.get_channel_response = channels.getByIndex(channelIndex);
|
||||||
r.which_variant = AdminMessage_get_channel_response_tag;
|
r.which_variant = AdminMessage_get_channel_response_tag;
|
||||||
reply = allocDataProtobuf(r);
|
myReply = allocDataProtobuf(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ void AdminPlugin::handleGetRadio(const MeshPacket &req)
|
|||||||
r.get_radio_response.preferences.ls_secs = getPref_ls_secs();
|
r.get_radio_response.preferences.ls_secs = getPref_ls_secs();
|
||||||
|
|
||||||
r.which_variant = AdminMessage_get_radio_response_tag;
|
r.which_variant = AdminMessage_get_radio_response_tag;
|
||||||
reply = allocDataProtobuf(r);
|
myReply = allocDataProtobuf(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessag
|
|||||||
case AdminMessage_set_channel_tag:
|
case AdminMessage_set_channel_tag:
|
||||||
DEBUG_MSG("Client is setting channel %d\n", r->set_channel.index);
|
DEBUG_MSG("Client is setting channel %d\n", r->set_channel.index);
|
||||||
if (r->set_channel.index < 0 || r->set_channel.index >= (int)MAX_NUM_CHANNELS)
|
if (r->set_channel.index < 0 || r->set_channel.index >= (int)MAX_NUM_CHANNELS)
|
||||||
reply = allocErrorResponse(Routing_Error_BAD_REQUEST, &mp);
|
myReply = allocErrorResponse(Routing_Error_BAD_REQUEST, &mp);
|
||||||
else
|
else
|
||||||
handleSetChannel(r->set_channel);
|
handleSetChannel(r->set_channel);
|
||||||
break;
|
break;
|
||||||
@ -66,7 +66,7 @@ bool AdminPlugin::handleReceivedProtobuf(const MeshPacket &mp, const AdminMessag
|
|||||||
uint32_t i = r->get_channel_request - 1;
|
uint32_t i = r->get_channel_request - 1;
|
||||||
DEBUG_MSG("Client is getting channel %u\n", i);
|
DEBUG_MSG("Client is getting channel %u\n", i);
|
||||||
if (i >= MAX_NUM_CHANNELS)
|
if (i >= MAX_NUM_CHANNELS)
|
||||||
reply = allocErrorResponse(Routing_Error_BAD_REQUEST, &mp);
|
myReply = allocErrorResponse(Routing_Error_BAD_REQUEST, &mp);
|
||||||
else
|
else
|
||||||
handleGetChannel(mp, i);
|
handleGetChannel(mp, i);
|
||||||
break;
|
break;
|
||||||
@ -141,13 +141,6 @@ void AdminPlugin::handleSetRadio(const RadioConfig &r)
|
|||||||
service.reloadConfig();
|
service.reloadConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshPacket *AdminPlugin::allocReply()
|
|
||||||
{
|
|
||||||
auto r = reply;
|
|
||||||
reply = NULL; // Only use each reply once
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
AdminPlugin::AdminPlugin() : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
|
AdminPlugin::AdminPlugin() : ProtobufPlugin("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
|
||||||
{
|
{
|
||||||
// restrict to the admin channel for rx
|
// restrict to the admin channel for rx
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
*/
|
*/
|
||||||
class AdminPlugin : public ProtobufPlugin<AdminMessage>
|
class AdminPlugin : public ProtobufPlugin<AdminMessage>
|
||||||
{
|
{
|
||||||
MeshPacket *reply = NULL;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructor
|
/** Constructor
|
||||||
* name is for debugging output
|
* name is for debugging output
|
||||||
@ -21,10 +19,6 @@ class AdminPlugin : public ProtobufPlugin<AdminMessage>
|
|||||||
*/
|
*/
|
||||||
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const AdminMessage *p);
|
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const AdminMessage *p);
|
||||||
|
|
||||||
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
|
||||||
* so that subclasses can (optionally) send a response back to the original sender. */
|
|
||||||
virtual MeshPacket *allocReply();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleSetOwner(const User &o);
|
void handleSetOwner(const User &o);
|
||||||
void handleSetChannel(const Channel &cc);
|
void handleSetChannel(const Channel &cc);
|
||||||
|
@ -10,12 +10,13 @@
|
|||||||
|
|
||||||
// Because (FIXME) we currently don't tell API clients status on sent messages
|
// Because (FIXME) we currently don't tell API clients status on sent messages
|
||||||
// we need to throttle our sending, so that if a gpio is bouncing up and down we
|
// we need to throttle our sending, so that if a gpio is bouncing up and down we
|
||||||
// don't generate more messages than the net can send. So we limit watch messages to
|
// don't generate more messages than the net can send. So we limit watch messages to
|
||||||
// a max of one change per 30 seconds
|
// a max of one change per 30 seconds
|
||||||
#define WATCH_INTERVAL_MSEC (30 * 1000)
|
#define WATCH_INTERVAL_MSEC (30 * 1000)
|
||||||
|
|
||||||
/// Set pin modes for every set bit in a mask
|
/// Set pin modes for every set bit in a mask
|
||||||
static void pinModes(uint64_t mask, uint8_t mode) {
|
static void pinModes(uint64_t mask, uint8_t mode)
|
||||||
|
{
|
||||||
for (uint8_t i = 0; i < NUM_GPIOS; i++) {
|
for (uint8_t i = 0; i < NUM_GPIOS; i++) {
|
||||||
if (mask & (1 << i)) {
|
if (mask & (1 << i)) {
|
||||||
pinMode(i, mode);
|
pinMode(i, mode);
|
||||||
@ -24,7 +25,8 @@ static void pinModes(uint64_t mask, uint8_t mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read all the pins mentioned in a mask
|
/// Read all the pins mentioned in a mask
|
||||||
static uint64_t digitalReads(uint64_t mask) {
|
static uint64_t digitalReads(uint64_t mask)
|
||||||
|
{
|
||||||
uint64_t res = 0;
|
uint64_t res = 0;
|
||||||
|
|
||||||
pinModes(mask, INPUT_PULLUP);
|
pinModes(mask, INPUT_PULLUP);
|
||||||
@ -40,10 +42,9 @@ static uint64_t digitalReads(uint64_t mask) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RemoteHardwarePlugin::RemoteHardwarePlugin()
|
RemoteHardwarePlugin::RemoteHardwarePlugin()
|
||||||
: ProtobufPlugin("remotehardware", PortNum_REMOTE_HARDWARE_APP, HardwareMessage_fields),
|
: ProtobufPlugin("remotehardware", PortNum_REMOTE_HARDWARE_APP, HardwareMessage_fields), concurrency::OSThread(
|
||||||
concurrency::OSThread("remotehardware")
|
"remotehardware")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,26 +70,26 @@ bool RemoteHardwarePlugin::handleReceivedProtobuf(const MeshPacket &req, const H
|
|||||||
|
|
||||||
case HardwareMessage_Type_READ_GPIOS: {
|
case HardwareMessage_Type_READ_GPIOS: {
|
||||||
// Print notification to LCD screen
|
// Print notification to LCD screen
|
||||||
if(screen)
|
if (screen)
|
||||||
screen->print("Read GPIOs\n");
|
screen->print("Read GPIOs\n");
|
||||||
|
|
||||||
uint64_t res = digitalReads(p.gpio_mask);
|
uint64_t res = digitalReads(p.gpio_mask);
|
||||||
|
|
||||||
// Send the reply
|
// Send the reply
|
||||||
HardwareMessage reply = HardwareMessage_init_default;
|
HardwareMessage r = HardwareMessage_init_default;
|
||||||
reply.typ = HardwareMessage_Type_READ_GPIOS_REPLY;
|
r.typ = HardwareMessage_Type_READ_GPIOS_REPLY;
|
||||||
reply.gpio_value = res;
|
r.gpio_value = res;
|
||||||
MeshPacket *p = allocDataProtobuf(reply);
|
MeshPacket *p = allocDataProtobuf(r);
|
||||||
setReplyTo(p, req);
|
setReplyTo(p, req);
|
||||||
service.sendToMesh(p);
|
myReply = p;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case HardwareMessage_Type_WATCH_GPIOS: {
|
case HardwareMessage_Type_WATCH_GPIOS: {
|
||||||
watchGpios = p.gpio_mask;
|
watchGpios = p.gpio_mask;
|
||||||
lastWatchMsec = 0; // Force a new publish soon
|
lastWatchMsec = 0; // Force a new publish soon
|
||||||
previousWatch = ~watchGpios; // generate a 'previous' value which is guaranteed to not match (to force an initial publish)
|
previousWatch = ~watchGpios; // generate a 'previous' value which is guaranteed to not match (to force an initial publish)
|
||||||
enabled = true; // Let our thread run at least once
|
enabled = true; // Let our thread run at least once
|
||||||
DEBUG_MSG("Now watching GPIOs 0x%llx\n", watchGpios);
|
DEBUG_MSG("Now watching GPIOs 0x%llx\n", watchGpios);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -101,31 +102,31 @@ bool RemoteHardwarePlugin::handleReceivedProtobuf(const MeshPacket &req, const H
|
|||||||
DEBUG_MSG("Hardware operation %d not yet implemented! FIXME\n", p.typ);
|
DEBUG_MSG("Hardware operation %d not yet implemented! FIXME\n", p.typ);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true; // handled
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t RemoteHardwarePlugin::runOnce() {
|
int32_t RemoteHardwarePlugin::runOnce()
|
||||||
if(watchGpios) {
|
{
|
||||||
|
if (watchGpios) {
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
|
|
||||||
if(now - lastWatchMsec >= WATCH_INTERVAL_MSEC) {
|
if (now - lastWatchMsec >= WATCH_INTERVAL_MSEC) {
|
||||||
uint64_t curVal = digitalReads(watchGpios);
|
uint64_t curVal = digitalReads(watchGpios);
|
||||||
|
|
||||||
if(curVal != previousWatch) {
|
if (curVal != previousWatch) {
|
||||||
previousWatch = curVal;
|
previousWatch = curVal;
|
||||||
DEBUG_MSG("Broadcasting GPIOS 0x%llx changed!\n", curVal);
|
DEBUG_MSG("Broadcasting GPIOS 0x%llx changed!\n", curVal);
|
||||||
|
|
||||||
// Something changed! Tell the world with a broadcast message
|
// Something changed! Tell the world with a broadcast message
|
||||||
HardwareMessage reply = HardwareMessage_init_default;
|
HardwareMessage r = HardwareMessage_init_default;
|
||||||
reply.typ = HardwareMessage_Type_GPIOS_CHANGED;
|
r.typ = HardwareMessage_Type_GPIOS_CHANGED;
|
||||||
reply.gpio_value = curVal;
|
r.gpio_value = curVal;
|
||||||
MeshPacket *p = allocDataProtobuf(reply);
|
MeshPacket *p = allocDataProtobuf(r);
|
||||||
service.sendToMesh(p);
|
service.sendToMesh(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// No longer watching anything - stop using CPU
|
// No longer watching anything - stop using CPU
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user