mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-25 22:20:27 +00:00
commit
50ec03229f
@ -1,11 +1,13 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
pio run
|
TARG=tbeam
|
||||||
|
|
||||||
|
pio run -e $TARG
|
||||||
|
|
||||||
echo uploading to usb1
|
echo uploading to usb1
|
||||||
pio run --upload-port /dev/ttyUSB1 -t upload &
|
pio run --upload-port /dev/ttyUSB1 -t upload -e $TARG &
|
||||||
|
|
||||||
echo uploading to usb0
|
echo uploading to usb0
|
||||||
pio run --upload-port /dev/ttyUSB0 -t upload &
|
pio run --upload-port /dev/ttyUSB0 -t upload -e $TARG &
|
||||||
|
|
||||||
wait
|
wait
|
||||||
|
@ -4,7 +4,7 @@ You probably don't care about this section - skip to the next one.
|
|||||||
|
|
||||||
## before next release
|
## before next release
|
||||||
|
|
||||||
* android speed settings https://github.com/meshtastic/Meshtastic-Android/issues/271
|
* DONE android speed settings https://github.com/meshtastic/Meshtastic-Android/issues/271
|
||||||
* fix heltec battery scaling
|
* fix heltec battery scaling
|
||||||
|
|
||||||
* DONE remote admin busted?
|
* DONE remote admin busted?
|
||||||
|
@ -1,23 +1,60 @@
|
|||||||
# Remote Hardware Service
|
# Remote Hardware Service
|
||||||
|
|
||||||
FIXME - the following are a collection of notes moved from elsewhere. We need to refactor these notes into actual documentation on the remote-hardware/gpio service.
|
These are 'programmer focused' notes on using the "remote hardware" feature.
|
||||||
|
|
||||||
### 1.7.2. New 'no-code-IOT' mini-app
|
Note: This feature uses a preinstalled plugin in the device code and associated commandline flags/classes in the python code. You'll need to be running at least version 1.2.23 (or later) of the python and device code to use this feature.
|
||||||
|
|
||||||
Add a new 'remote GPIO/serial port/SPI/I2C access' mini-app. This new standard app would use the MQTT messaging layer to let users (developers that don't need to write device code) do basic (potentially dangerous) operations remotely.
|
You can get the latest python tool/library with "pip3 install --upgrade meshtastic" on Windows/Linux/OS-X.
|
||||||
|
|
||||||
#### 1.7.2.1. Supported operations in the initial release
|
## Supported operations in the initial release
|
||||||
|
|
||||||
Initially supported features for no-code-IOT.
|
|
||||||
|
|
||||||
- Set any GPIO
|
- Set any GPIO
|
||||||
- Read any GPIO
|
- Read any GPIO
|
||||||
|
- Receive notification of changes in any GPIO.
|
||||||
|
|
||||||
#### 1.7.2.2. Supported operations eventually
|
## Setup
|
||||||
|
|
||||||
General ideas for no-code IOT.
|
GPIO access is fundamentally 'dangerous' because invalid options can physically burn-up hardware. To prevent access from untrusted users you must first make a "gpio" channel that is used for authenticated access to this feature. You'll need to install this channel on both the local and remote node.
|
||||||
|
|
||||||
- Subscribe for notification of GPIO input status change (i.e. when pin goes low, send my app a message)
|
The procedure using the python command line tool is:
|
||||||
- Write/read N bytes over I2C/SPI bus Y (as one atomic I2C/SPI transaction)
|
|
||||||
- Send N bytes out serial port Z
|
1. Connect local device via USB
|
||||||
- Subscribe for notification for when regex X matches the bytes that were received on serial port Z
|
2. "meshtastic --ch-add admin; meshtastic --info" thn copy the (long) "Complete URL" that info printed
|
||||||
|
3. Connect remote device via USB (or use the remote admin feature to reach it through the mesh, but that's beyond the scope of this tutorial)
|
||||||
|
4. "meshtastic --seturl theurlyoucopiedinstep2"
|
||||||
|
|
||||||
|
Now both devices can talk over the "gpio" channel.
|
||||||
|
|
||||||
|
## Doing GPIO operations
|
||||||
|
|
||||||
|
Here's some examples using the command line tool.
|
||||||
|
|
||||||
|
## Using GPIOs from python
|
||||||
|
|
||||||
|
You can programmatically do operations from your own python code by using the meshtastic "RemoteHardwareClient" class - see the python documentation for more details.
|
||||||
|
|
||||||
|
Writing a GPIO
|
||||||
|
```
|
||||||
|
meshtastic --port /dev/ttyUSB0 --gpio-wrb 4 1 --dest \!28979058
|
||||||
|
Connected to radio
|
||||||
|
Writing GPIO mask 0x10 with value 0x10 to !28979058
|
||||||
|
```
|
||||||
|
|
||||||
|
Reading a GPIO
|
||||||
|
```
|
||||||
|
meshtastic --port /dev/ttyUSB0 --gpio-rd 0x10 --dest \!28979058
|
||||||
|
Connected to radio
|
||||||
|
Reading GPIO mask 0x10 from !28979058
|
||||||
|
GPIO read response gpio_value=16
|
||||||
|
```
|
||||||
|
|
||||||
|
Watching for GPIO changes:
|
||||||
|
```
|
||||||
|
meshtastic --port /dev/ttyUSB0 --gpio-watch 0x10 --dest \!28979058
|
||||||
|
Connected to radio
|
||||||
|
Watching GPIO mask 0x10 from !28979058
|
||||||
|
Received RemoteHardware typ=GPIOS_CHANGED, gpio_value=16
|
||||||
|
Received RemoteHardware typ=GPIOS_CHANGED, gpio_value=0
|
||||||
|
Received RemoteHardware typ=GPIOS_CHANGED, gpio_value=16
|
||||||
|
< press ctrl-c to exit >
|
||||||
|
```
|
@ -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
|
||||||
|
@ -75,11 +75,6 @@ void MQTT::reconnect()
|
|||||||
enabled = true; // Start running background process again
|
enabled = true; // Start running background process again
|
||||||
runASAP = true;
|
runASAP = true;
|
||||||
|
|
||||||
static char subsStr[64]; /* We keep this static because the mqtt lib
|
|
||||||
might not be copying it */
|
|
||||||
// snprintf(subsStr, sizeof(subsStr), "/ezd/todev/%s/#", clientId);
|
|
||||||
// pubSub.subscribe(subsStr, 1); // we use qos 1 because we don't want to miss messages
|
|
||||||
|
|
||||||
/// FIXME, include more information in the status text
|
/// FIXME, include more information in the status text
|
||||||
bool ok = pubSub.publish(myStatus.c_str(), "online", true);
|
bool ok = pubSub.publish(myStatus.c_str(), "online", true);
|
||||||
DEBUG_MSG("published %d\n", ok);
|
DEBUG_MSG("published %d\n", ok);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
[VERSION]
|
[VERSION]
|
||||||
major = 1
|
major = 1
|
||||||
minor = 2
|
minor = 2
|
||||||
build = 20
|
build = 23
|
||||||
|
Loading…
Reference in New Issue
Block a user