mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-15 07:12:34 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f0e704f29 | ||
|
|
23aaee737a | ||
|
|
42c46cad41 | ||
|
|
f0b72a4b4b | ||
|
|
24ca4602b1 |
8
.github/workflows/build_firmware.yml
vendored
8
.github/workflows/build_firmware.yml
vendored
@@ -56,18 +56,16 @@ jobs:
|
||||
ota_firmware_source: ${{ steps.ota_dir.outputs.src || '' }}
|
||||
ota_firmware_target: ${{ steps.ota_dir.outputs.tgt || '' }}
|
||||
|
||||
- name: Job summary
|
||||
- name: Echo manifest from release/firmware-*.mt.json to job summary
|
||||
if: ${{ always() }}
|
||||
env:
|
||||
PIO_ENV: ${{ inputs.pio_env }}
|
||||
run: |
|
||||
echo "## $PIO_ENV" >> $GITHUB_STEP_SUMMARY
|
||||
echo "<details><summary><strong>Manifest</strong></summary>" >> $GITHUB_STEP_SUMMARY
|
||||
echo '' >> $GITHUB_STEP_SUMMARY
|
||||
echo "## Manifest: \`$PIO_ENV\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```json' >> $GITHUB_STEP_SUMMARY
|
||||
cat release/firmware-*.mt.json >> $GITHUB_STEP_SUMMARY
|
||||
echo '' >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
echo "</details>" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
|
||||
17
.github/workflows/main_matrix.yml
vendored
17
.github/workflows/main_matrix.yml
vendored
@@ -77,21 +77,16 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
check: ${{ fromJson(needs.setup.outputs.check) }}
|
||||
# Use 'arctastic' self-hosted runner pool when checking in the main repo
|
||||
runs-on: ${{ github.repository_owner == 'meshtastic' && 'arctastic' || 'ubuntu-latest' }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
- name: Build base
|
||||
id: base
|
||||
uses: ./.github/actions/setup-base
|
||||
- name: Check ${{ matrix.check.board }}
|
||||
uses: meshtastic/gh-action-firmware@main
|
||||
with:
|
||||
pio_platform: ${{ matrix.check.platform }}
|
||||
pio_env: ${{ matrix.check.board }}
|
||||
pio_target: check
|
||||
run: bin/check-all.sh ${{ matrix.check.board }}
|
||||
|
||||
build:
|
||||
needs: [setup, version]
|
||||
|
||||
2
.github/workflows/release_channels.yml
vendored
2
.github/workflows/release_channels.yml
vendored
@@ -102,7 +102,7 @@ jobs:
|
||||
PIP_DISABLE_PIP_VERSION_CHECK: 1
|
||||
|
||||
- name: Create Bumps pull request
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
base: ${{ github.event.repository.default_branch }}
|
||||
branch: create-pull-request/bump-version
|
||||
|
||||
2
.github/workflows/update_protobufs.yml
vendored
2
.github/workflows/update_protobufs.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
./bin/regen-protos.sh
|
||||
|
||||
- name: Create pull request
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
branch: create-pull-request/update-protobufs
|
||||
labels: submodules
|
||||
|
||||
@@ -9,24 +9,24 @@ plugins:
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@3.2.495
|
||||
- renovate@42.42.2
|
||||
- renovate@42.30.4
|
||||
- prettier@3.7.4
|
||||
- trufflehog@3.92.1
|
||||
- trufflehog@3.91.2
|
||||
- yamllint@1.37.1
|
||||
- bandit@1.9.2
|
||||
- trivy@0.68.1
|
||||
- trivy@0.67.2
|
||||
- taplo@0.10.0
|
||||
- ruff@0.14.8
|
||||
- ruff@0.14.7
|
||||
- isort@7.0.0
|
||||
- markdownlint@0.46.0
|
||||
- oxipng@10.0.0
|
||||
- oxipng@9.1.5
|
||||
- svgo@4.0.0
|
||||
- actionlint@1.7.9
|
||||
- flake8@7.3.0
|
||||
- hadolint@2.14.0
|
||||
- shfmt@3.6.0
|
||||
- shellcheck@0.11.0
|
||||
- black@25.12.0
|
||||
- black@25.11.0
|
||||
- git-diff-check
|
||||
- gitleaks@8.30.0
|
||||
- clang-format@16.0.3
|
||||
|
||||
@@ -22,7 +22,7 @@ export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 -t mtjson # -v
|
||||
pio run --environment $1 # -v
|
||||
|
||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||
|
||||
@@ -32,10 +32,20 @@ cp $BUILDDIR/$basename.factory.bin $OUTDIR/$basename.factory.bin
|
||||
echo "Copying ESP32 update bin file"
|
||||
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
|
||||
|
||||
echo "Copying Filesystem for ESP32 targets"
|
||||
echo "Building Filesystem for ESP32 targets"
|
||||
# If you want to build the webui, uncomment the following lines
|
||||
# pio run --environment $1 -t buildfs
|
||||
# cp .pio/build/$1/littlefs.bin $OUTDIR/littlefswebui-$1-$VERSION.bin
|
||||
# # Remove webserver files from the filesystem and rebuild
|
||||
# ls -l data/static # Diagnostic list of files
|
||||
# rm -rf data/static
|
||||
pio run --environment $1 -t buildfs --disable-auto-clean
|
||||
cp $BUILDDIR/littlefs-$1-$VERSION.bin $OUTDIR/littlefs-$1-$VERSION.bin
|
||||
cp bin/device-install.* $OUTDIR/
|
||||
cp bin/device-update.* $OUTDIR/
|
||||
|
||||
echo "Copying manifest"
|
||||
# Generate the manifest file
|
||||
echo "Generating Meshtastic manifest"
|
||||
TIMEFORMAT="Generated manifest in %E seconds"
|
||||
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -22,7 +22,7 @@ export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 -t mtjson # -v
|
||||
pio run --environment $1 # -v
|
||||
|
||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||
|
||||
@@ -47,5 +47,8 @@ if (echo $1 | grep -q "rak4631"); then
|
||||
cp $SRCHEX $OUTDIR/
|
||||
fi
|
||||
|
||||
echo "Copying manifest"
|
||||
# Generate the manifest file
|
||||
echo "Generating Meshtastic manifest"
|
||||
TIMEFORMAT="Generated manifest in %E seconds"
|
||||
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -22,12 +22,15 @@ export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 -t mtjson # -v
|
||||
pio run --environment $1 # -v
|
||||
|
||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||
|
||||
echo "Copying uf2 file"
|
||||
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
|
||||
|
||||
echo "Copying manifest"
|
||||
# Generate the manifest file
|
||||
echo "Generating Meshtastic manifest"
|
||||
TIMEFORMAT="Generated manifest in %E seconds"
|
||||
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -22,12 +22,15 @@ export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 -t mtjson # -v
|
||||
pio run --environment $1 # -v
|
||||
|
||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||
|
||||
echo "Copying STM32 bin file"
|
||||
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
|
||||
|
||||
echo "Copying manifest"
|
||||
# Generate the manifest file
|
||||
echo "Generating Meshtastic manifest"
|
||||
TIMEFORMAT="Generated manifest in %E seconds"
|
||||
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -159,22 +159,20 @@ def load_boot_logo(source, target, env):
|
||||
|
||||
# Load the boot logo on TFT builds
|
||||
if ("HAS_TFT", 1) in env.get("CPPDEFINES", []):
|
||||
env.AddPreAction(f"$BUILD_DIR/{lfsbin}", load_boot_logo)
|
||||
env.AddPreAction('$BUILD_DIR/littlefs.bin', load_boot_logo)
|
||||
|
||||
mtjson_deps = ["buildprog"]
|
||||
if platform.name == "espressif32":
|
||||
# Build littlefs image as part of mtjson target
|
||||
# Equivalent to `pio run -t buildfs`
|
||||
target_lfs = env.DataToBin(
|
||||
join("$BUILD_DIR", "${ESP32_FS_IMAGE_NAME}"), "$PROJECT_DATA_DIR"
|
||||
)
|
||||
mtjson_deps.append(target_lfs)
|
||||
# Rename (mv) littlefs.bin to include the PROGNAME
|
||||
# This ensures the littlefs.bin is named consistently with the firmware
|
||||
env.AddPostAction('$BUILD_DIR/littlefs.bin', env.VerboseAction(
|
||||
f'mv $BUILD_DIR/littlefs.bin $BUILD_DIR/{lfsbin}',
|
||||
f'Renaming littlefs.bin to {lfsbin}'
|
||||
))
|
||||
|
||||
env.AddCustomTarget(
|
||||
name="mtjson",
|
||||
dependencies=mtjson_deps,
|
||||
dependencies=None,
|
||||
actions=[manifest_gather],
|
||||
title="Meshtastic Manifest",
|
||||
description="Generating Meshtastic manifest JSON + Checksums",
|
||||
always_build=False,
|
||||
always_build=True,
|
||||
)
|
||||
|
||||
@@ -11,9 +11,6 @@ else:
|
||||
prefsLoc = env["PROJECT_DIR"] + "/version.properties"
|
||||
verObj = readProps(prefsLoc)
|
||||
env.Replace(PROGNAME=f"firmware-{env.get('PIOENV')}-{verObj['long']}")
|
||||
env.Replace(ESP32_FS_IMAGE_NAME=f"littlefs-{env.get('PIOENV')}-{verObj['long']}")
|
||||
|
||||
# Print the new program name for verification
|
||||
print(f"PROGNAME: {env.get('PROGNAME')}")
|
||||
if platform.name == "espressif32":
|
||||
print(f"ESP32_FS_IMAGE_NAME: {env.get('ESP32_FS_IMAGE_NAME')}")
|
||||
|
||||
@@ -10,12 +10,6 @@ Import("env")
|
||||
platform = env.PioPlatform()
|
||||
|
||||
sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
|
||||
# IntelHex workaround, remove after fixed upstream
|
||||
# https://github.com/platformio/platform-espressif32/issues/1632
|
||||
try:
|
||||
import intelhex
|
||||
except ImportError:
|
||||
env.Execute("$PYTHONEXE -m pip install intelhex")
|
||||
import esptool
|
||||
|
||||
|
||||
|
||||
@@ -532,10 +532,8 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
const int labelX = x;
|
||||
int barsOffset = (isHighResolution) ? 24 : 0;
|
||||
#ifdef USE_EINK
|
||||
#ifndef T_DECK_PRO
|
||||
barsOffset -= 12;
|
||||
#endif
|
||||
#endif
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
const int barX = x + 45 + barsOffset;
|
||||
#else
|
||||
@@ -576,7 +574,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
#endif
|
||||
// Value string
|
||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display->drawString(SCREEN_WIDTH, getTextPositions(display)[line], combinedStr);
|
||||
display->drawString(SCREEN_WIDTH - 2, getTextPositions(display)[line], combinedStr);
|
||||
};
|
||||
|
||||
// === Memory values ===
|
||||
|
||||
@@ -428,17 +428,10 @@ void setup()
|
||||
#endif
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
RTCQuality ourQuality = RTCQualityDevice;
|
||||
|
||||
std::string timeCommandResult = exec("timedatectl status | grep synchronized | grep yes -c");
|
||||
if (timeCommandResult[0] == '1') {
|
||||
ourQuality = RTCQualityNTP;
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = time(NULL);
|
||||
tv.tv_usec = 0;
|
||||
perhapsSetRTC(ourQuality, &tv);
|
||||
perhapsSetRTC(RTCQualityDevice, &tv);
|
||||
#endif
|
||||
|
||||
powerMonInit();
|
||||
|
||||
@@ -96,8 +96,6 @@ class Channels
|
||||
|
||||
bool setDefaultPresetCryptoForHash(ChannelHash channelHash);
|
||||
|
||||
int16_t getHash(ChannelIndex i) { return hashes[i]; }
|
||||
|
||||
private:
|
||||
/** Given a channel index, change to use the crypto key specified by that index
|
||||
*
|
||||
@@ -115,6 +113,8 @@ class Channels
|
||||
*/
|
||||
int16_t generateHash(ChannelIndex channelNum);
|
||||
|
||||
int16_t getHash(ChannelIndex i) { return hashes[i]; }
|
||||
|
||||
/**
|
||||
* Validate a channel, fixing any errors as needed
|
||||
*/
|
||||
|
||||
@@ -225,4 +225,4 @@ class MeshModule
|
||||
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
|
||||
* This ensures that if the request packet was sent reliably, the reply is sent that way as well.
|
||||
*/
|
||||
void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to);
|
||||
void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to);
|
||||
@@ -805,15 +805,11 @@ void NodeDB::installDefaultModuleConfig()
|
||||
moduleConfig.external_notification.output_ms = 500;
|
||||
moduleConfig.external_notification.nag_timeout = 2;
|
||||
#endif
|
||||
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) || defined(MUZI_BASE)
|
||||
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312)
|
||||
// Default to RAK led pin 2 (blue)
|
||||
moduleConfig.external_notification.enabled = true;
|
||||
moduleConfig.external_notification.output = PIN_LED2;
|
||||
#if defined(MUZI_BASE)
|
||||
moduleConfig.external_notification.active = false;
|
||||
#else
|
||||
moduleConfig.external_notification.active = true;
|
||||
#endif
|
||||
moduleConfig.external_notification.alert_message = true;
|
||||
moduleConfig.external_notification.output_ms = 1000;
|
||||
moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs;
|
||||
|
||||
@@ -150,9 +150,7 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
|
||||
PacketId nakId = (c && c->error_reason != meshtastic_Routing_Error_NONE) ? p->decoded.request_id : 0;
|
||||
|
||||
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
|
||||
if ((ackId || nakId) &&
|
||||
// Implicit ACKs from MQTT should not stop retransmissions
|
||||
!(isFromUs(p) && p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MQTT)) {
|
||||
if (ackId || nakId) {
|
||||
LOG_DEBUG("Received a %s for 0x%x, stopping retransmissions", ackId ? "ACK" : "NAK", ackId);
|
||||
if (ackId) {
|
||||
stopRetransmission(p->to, ackId);
|
||||
|
||||
@@ -688,7 +688,7 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
||||
|
||||
// Store a copy of encrypted packet for MQTT
|
||||
DEBUG_HEAP_BEFORE;
|
||||
p_encrypted = packetPool.allocCopy(*p);
|
||||
meshtastic_MeshPacket *p_encrypted = packetPool.allocCopy(*p);
|
||||
DEBUG_HEAP_AFTER("Router::handleReceived", p_encrypted);
|
||||
|
||||
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
||||
|
||||
@@ -91,9 +91,6 @@ class Router : protected concurrency::OSThread, protected PacketHistory
|
||||
before us */
|
||||
uint32_t rxDupe = 0, txRelayCanceled = 0;
|
||||
|
||||
// pointer to the encrypted packet
|
||||
meshtastic_MeshPacket *p_encrypted;
|
||||
|
||||
protected:
|
||||
friend class RoutingModule;
|
||||
|
||||
|
||||
@@ -24,9 +24,6 @@ PB_BIND(meshtastic_Data, meshtastic_Data, 2)
|
||||
PB_BIND(meshtastic_KeyVerification, meshtastic_KeyVerification, AUTO)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_StoreForwardPlusPlus, meshtastic_StoreForwardPlusPlus, 2)
|
||||
|
||||
|
||||
PB_BIND(meshtastic_Waypoint, meshtastic_Waypoint, AUTO)
|
||||
|
||||
|
||||
@@ -124,8 +121,6 @@ PB_BIND(meshtastic_ChunkedPayloadResponse, meshtastic_ChunkedPayloadResponse, AU
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -478,17 +478,6 @@ typedef enum _meshtastic_Routing_Error {
|
||||
meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED = 38
|
||||
} meshtastic_Routing_Error;
|
||||
|
||||
/* enum message type? */
|
||||
typedef enum _meshtastic_StoreForwardPlusPlus_SFPP_message_type {
|
||||
/* message hash without chain hash means that no, it is not on the chain */
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE = 0,
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_CHAIN_QUERY = 1,
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_REQUEST = 3,
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE = 4,
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_FIRSTHALF = 5,
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF = 6
|
||||
} meshtastic_StoreForwardPlusPlus_SFPP_message_type;
|
||||
|
||||
/* The priority of this message for sending.
|
||||
Higher priorities are sent first (when managing the transmit queue).
|
||||
This field is never sent over the air, it is only used internally inside of a local device node.
|
||||
@@ -793,24 +782,6 @@ typedef struct _meshtastic_KeyVerification {
|
||||
meshtastic_KeyVerification_hash2_t hash2;
|
||||
} meshtastic_KeyVerification;
|
||||
|
||||
typedef PB_BYTES_ARRAY_T(32) meshtastic_StoreForwardPlusPlus_message_hash_t;
|
||||
typedef PB_BYTES_ARRAY_T(32) meshtastic_StoreForwardPlusPlus_chain_hash_t;
|
||||
typedef PB_BYTES_ARRAY_T(32) meshtastic_StoreForwardPlusPlus_root_hash_t;
|
||||
typedef PB_BYTES_ARRAY_T(240) meshtastic_StoreForwardPlusPlus_message_t;
|
||||
/* The actual over-the-mesh message doing store and forward++ */
|
||||
typedef struct _meshtastic_StoreForwardPlusPlus { /* */
|
||||
meshtastic_StoreForwardPlusPlus_SFPP_message_type sfpp_message_type;
|
||||
meshtastic_StoreForwardPlusPlus_message_hash_t message_hash;
|
||||
meshtastic_StoreForwardPlusPlus_chain_hash_t chain_hash;
|
||||
meshtastic_StoreForwardPlusPlus_root_hash_t root_hash;
|
||||
/* encapsulated message to share (may be split in half) */
|
||||
meshtastic_StoreForwardPlusPlus_message_t message;
|
||||
uint32_t encapsulated_id;
|
||||
uint32_t encapsulated_to;
|
||||
uint32_t encapsulated_from;
|
||||
uint32_t encapsulated_rxtime;
|
||||
} meshtastic_StoreForwardPlusPlus;
|
||||
|
||||
/* Waypoint message, used to share arbitrary locations across the mesh */
|
||||
typedef struct _meshtastic_Waypoint {
|
||||
/* Id of the waypoint */
|
||||
@@ -1339,10 +1310,6 @@ extern "C" {
|
||||
#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED
|
||||
#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED+1))
|
||||
|
||||
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE
|
||||
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MAX meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF
|
||||
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_ARRAYSIZE ((meshtastic_StoreForwardPlusPlus_SFPP_message_type)(meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF+1))
|
||||
|
||||
#define _meshtastic_MeshPacket_Priority_MIN meshtastic_MeshPacket_Priority_UNSET
|
||||
#define _meshtastic_MeshPacket_Priority_MAX meshtastic_MeshPacket_Priority_MAX
|
||||
#define _meshtastic_MeshPacket_Priority_ARRAYSIZE ((meshtastic_MeshPacket_Priority)(meshtastic_MeshPacket_Priority_MAX+1))
|
||||
@@ -1371,8 +1338,6 @@ extern "C" {
|
||||
#define meshtastic_Data_portnum_ENUMTYPE meshtastic_PortNum
|
||||
|
||||
|
||||
#define meshtastic_StoreForwardPlusPlus_sfpp_message_type_ENUMTYPE meshtastic_StoreForwardPlusPlus_SFPP_message_type
|
||||
|
||||
|
||||
|
||||
#define meshtastic_MeshPacket_priority_ENUMTYPE meshtastic_MeshPacket_Priority
|
||||
@@ -1415,7 +1380,6 @@ extern "C" {
|
||||
#define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}}
|
||||
#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0}
|
||||
#define meshtastic_KeyVerification_init_default {0, {0, {0}}, {0, {0}}}
|
||||
#define meshtastic_StoreForwardPlusPlus_init_default {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0}
|
||||
#define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0}
|
||||
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
|
||||
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
|
||||
@@ -1447,7 +1411,6 @@ extern "C" {
|
||||
#define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}}
|
||||
#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0}
|
||||
#define meshtastic_KeyVerification_init_zero {0, {0, {0}}, {0, {0}}}
|
||||
#define meshtastic_StoreForwardPlusPlus_init_zero {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0}
|
||||
#define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0}
|
||||
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
|
||||
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
|
||||
@@ -1526,15 +1489,6 @@ extern "C" {
|
||||
#define meshtastic_KeyVerification_nonce_tag 1
|
||||
#define meshtastic_KeyVerification_hash1_tag 2
|
||||
#define meshtastic_KeyVerification_hash2_tag 3
|
||||
#define meshtastic_StoreForwardPlusPlus_sfpp_message_type_tag 1
|
||||
#define meshtastic_StoreForwardPlusPlus_message_hash_tag 2
|
||||
#define meshtastic_StoreForwardPlusPlus_chain_hash_tag 3
|
||||
#define meshtastic_StoreForwardPlusPlus_root_hash_tag 4
|
||||
#define meshtastic_StoreForwardPlusPlus_message_tag 5
|
||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_id_tag 6
|
||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_to_tag 7
|
||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_from_tag 8
|
||||
#define meshtastic_StoreForwardPlusPlus_encapsulated_rxtime_tag 9
|
||||
#define meshtastic_Waypoint_id_tag 1
|
||||
#define meshtastic_Waypoint_latitude_i_tag 2
|
||||
#define meshtastic_Waypoint_longitude_i_tag 3
|
||||
@@ -1751,19 +1705,6 @@ X(a, STATIC, SINGULAR, BYTES, hash2, 3)
|
||||
#define meshtastic_KeyVerification_CALLBACK NULL
|
||||
#define meshtastic_KeyVerification_DEFAULT NULL
|
||||
|
||||
#define meshtastic_StoreForwardPlusPlus_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UENUM, sfpp_message_type, 1) \
|
||||
X(a, STATIC, SINGULAR, BYTES, message_hash, 2) \
|
||||
X(a, STATIC, SINGULAR, BYTES, chain_hash, 3) \
|
||||
X(a, STATIC, SINGULAR, BYTES, root_hash, 4) \
|
||||
X(a, STATIC, SINGULAR, BYTES, message, 5) \
|
||||
X(a, STATIC, SINGULAR, UINT32, encapsulated_id, 6) \
|
||||
X(a, STATIC, SINGULAR, UINT32, encapsulated_to, 7) \
|
||||
X(a, STATIC, SINGULAR, UINT32, encapsulated_from, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, encapsulated_rxtime, 9)
|
||||
#define meshtastic_StoreForwardPlusPlus_CALLBACK NULL
|
||||
#define meshtastic_StoreForwardPlusPlus_DEFAULT NULL
|
||||
|
||||
#define meshtastic_Waypoint_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, id, 1) \
|
||||
X(a, STATIC, OPTIONAL, SFIXED32, latitude_i, 2) \
|
||||
@@ -2039,7 +1980,6 @@ extern const pb_msgdesc_t meshtastic_RouteDiscovery_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Routing_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Data_msg;
|
||||
extern const pb_msgdesc_t meshtastic_KeyVerification_msg;
|
||||
extern const pb_msgdesc_t meshtastic_StoreForwardPlusPlus_msg;
|
||||
extern const pb_msgdesc_t meshtastic_Waypoint_msg;
|
||||
extern const pb_msgdesc_t meshtastic_MqttClientProxyMessage_msg;
|
||||
extern const pb_msgdesc_t meshtastic_MeshPacket_msg;
|
||||
@@ -2073,7 +2013,6 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
|
||||
#define meshtastic_Routing_fields &meshtastic_Routing_msg
|
||||
#define meshtastic_Data_fields &meshtastic_Data_msg
|
||||
#define meshtastic_KeyVerification_fields &meshtastic_KeyVerification_msg
|
||||
#define meshtastic_StoreForwardPlusPlus_fields &meshtastic_StoreForwardPlusPlus_msg
|
||||
#define meshtastic_Waypoint_fields &meshtastic_Waypoint_msg
|
||||
#define meshtastic_MqttClientProxyMessage_fields &meshtastic_MqttClientProxyMessage_msg
|
||||
#define meshtastic_MeshPacket_fields &meshtastic_MeshPacket_msg
|
||||
@@ -2130,7 +2069,6 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
|
||||
#define meshtastic_QueueStatus_size 23
|
||||
#define meshtastic_RouteDiscovery_size 256
|
||||
#define meshtastic_Routing_size 259
|
||||
#define meshtastic_StoreForwardPlusPlus_size 371
|
||||
#define meshtastic_ToRadio_size 504
|
||||
#define meshtastic_User_size 115
|
||||
#define meshtastic_Waypoint_size 165
|
||||
|
||||
@@ -86,9 +86,6 @@ typedef enum _meshtastic_PortNum {
|
||||
/* Paxcounter lib included in the firmware
|
||||
ENCODING: protobuf */
|
||||
meshtastic_PortNum_PAXCOUNTER_APP = 34,
|
||||
/* Store and Forward++ module included in the firmware
|
||||
ENCODING: protobuf */
|
||||
meshtastic_PortNum_STORE_FORWARD_PLUSPLUS_APP = 35,
|
||||
/* Provides a hardware serial interface to send and receive from the Meshtastic network.
|
||||
Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic
|
||||
network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network.
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
#include "configuration.h"
|
||||
#include "input/InputBroker.h"
|
||||
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \
|
||||
!defined(CONFIG_IDF_TARGET_ESP32H2)
|
||||
#include <NonBlockingRtttl.h>
|
||||
#else
|
||||
// Noop class for portduino.
|
||||
|
||||
@@ -61,7 +61,6 @@
|
||||
#if ARCH_PORTDUINO
|
||||
#include "input/LinuxInputImpl.h"
|
||||
#include "input/SeesawRotary.h"
|
||||
#include "modules/Native/StoreForwardPlusPlus.h"
|
||||
#include "modules/Telemetry/HostMetrics.h"
|
||||
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
|
||||
#include "modules/StoreForwardModule.h"
|
||||
@@ -218,7 +217,7 @@ void setupModules()
|
||||
}
|
||||
#endif // HAS_BUTTON
|
||||
#if ARCH_PORTDUINO
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") {
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
seesawRotary = new SeesawRotary("SeesawRotary");
|
||||
if (!seesawRotary->init()) {
|
||||
delete seesawRotary;
|
||||
@@ -244,7 +243,6 @@ void setupModules()
|
||||
#endif
|
||||
#if ARCH_PORTDUINO
|
||||
new HostMetricsModule();
|
||||
new StoreForwardPlusPlusModule();
|
||||
#endif
|
||||
#if HAS_TELEMETRY
|
||||
new DeviceTelemetryModule();
|
||||
|
||||
@@ -1,653 +0,0 @@
|
||||
// create second module for satellites?
|
||||
|
||||
// The central node will generate a 256 or 128 bit value as its seed. This is the value other nodes subscribe to, and serves as
|
||||
// the root of the chain
|
||||
|
||||
//
|
||||
|
||||
// Basic design:
|
||||
// This module watches a channel for text messages.
|
||||
// each message gets sha256 summed, and then appended to a git-style blockchain. Probably need a counter, too
|
||||
// then the message, metadata, hash, and git hash information are saved. sqlite?
|
||||
|
||||
// nodes/sub-controllers can subscribe to a database
|
||||
|
||||
// A node can DM the controller, querying if a single message is on the chain, or asking for the last message hash
|
||||
|
||||
// if the message is not on the chain, the node can resend the message
|
||||
|
||||
// if the node lacks messages, it can request them
|
||||
|
||||
// will need the concept of sub-controllers, that subscribe to the central controller, can help push updates
|
||||
|
||||
// catch-up messages only go out when the mesh is low use %
|
||||
|
||||
// Normal firmware will only attempt to sync the chain a few times, then just ask for the latest few messages. A phone app can try
|
||||
// harder
|
||||
|
||||
// host will periodically advertise its presence
|
||||
|
||||
// at least initially, there can only be one authoritative host
|
||||
|
||||
// first draft is just to save channel 0 in a git-style database
|
||||
|
||||
// message objects get a hash value
|
||||
// the message chain gets a commit hash
|
||||
//
|
||||
|
||||
#include "StoreForwardPlusPlus.h"
|
||||
#include "MeshService.h"
|
||||
#include "RTC.h"
|
||||
#include "SHA256.h"
|
||||
#include "meshUtils.h"
|
||||
|
||||
StoreForwardPlusPlusModule::StoreForwardPlusPlusModule()
|
||||
: ProtobufModule("StoreForwardpp", meshtastic_PortNum_STORE_FORWARD_PLUSPLUS_APP, &meshtastic_StoreForwardPlusPlus_msg),
|
||||
concurrency::OSThread("StoreForwardpp")
|
||||
{
|
||||
LOG_WARN("StoreForwardPlusPlusModule init");
|
||||
if (portduino_config.sfpp_stratum0)
|
||||
LOG_WARN("SF++ stratum0");
|
||||
int res = sqlite3_open("test.db", &ppDb);
|
||||
LOG_WARN("Result1 %u", res);
|
||||
char *err = nullptr;
|
||||
res = sqlite3_exec(ppDb, " \
|
||||
CREATE TABLE channel_messages( \
|
||||
destination INT NOT NULL, \
|
||||
sender INT NOT NULL, \
|
||||
packet_id INT NOT NULL, \
|
||||
want_ack BOOL NOT NULL, \
|
||||
channel_hash INT NOT NULL, \
|
||||
encrypted_bytes BLOB NOT NULL, \
|
||||
message_hash BLOB NOT NULL, \
|
||||
rx_time INT NOT NULL, \
|
||||
commit_hash BLOB NOT NULL, \
|
||||
payload TEXT, \
|
||||
PRIMARY KEY (message_hash) \
|
||||
);",
|
||||
NULL, NULL, &err);
|
||||
LOG_WARN("Result2 %u", res);
|
||||
if (err != nullptr)
|
||||
;
|
||||
LOG_ERROR("%s", err);
|
||||
sqlite3_free(err);
|
||||
|
||||
// create table DMs
|
||||
res = sqlite3_exec(ppDb, " \
|
||||
CREATE TABLE direct_messages( \
|
||||
destination INT NOT NULL, \
|
||||
sender INT NOT NULL, \
|
||||
packet_id INT NOT NULL, \
|
||||
want_ack BOOL NOT NULL, \
|
||||
channel_hash INT NOT NULL, \
|
||||
commit_hash BLOB NOT NULL, \
|
||||
encrypted_bytes BLOB NOT NULL, \
|
||||
message_hash BLOB NOT NULL, \
|
||||
payload TEXT, \
|
||||
rx_time INT NOT NULL, \
|
||||
PRIMARY KEY (message_hash) \
|
||||
);",
|
||||
NULL, NULL, &err);
|
||||
LOG_WARN("Result2 %u", res);
|
||||
if (err != nullptr)
|
||||
;
|
||||
LOG_ERROR("%s", err);
|
||||
sqlite3_free(err);
|
||||
|
||||
// create table mappings
|
||||
// create table DMs
|
||||
res = sqlite3_exec(ppDb, " \
|
||||
CREATE TABLE mappings( \
|
||||
chain_type INT NOT NULL, \
|
||||
identifier INT NOT NULL, \
|
||||
root_hash BLOB NOT NULL, \
|
||||
PRIMARY KEY (identifier) \
|
||||
);",
|
||||
NULL, NULL, &err);
|
||||
LOG_WARN("Result2 %u", res);
|
||||
if (err != nullptr)
|
||||
;
|
||||
LOG_ERROR("%s", err);
|
||||
sqlite3_free(err);
|
||||
|
||||
// store schema version somewhere
|
||||
|
||||
std::string insert_statement = "INSERT INTO channel_messages (destination, sender, packet_id, want_ack, channel_hash, \
|
||||
encrypted_bytes, message_hash, rx_time, commit_hash, payload) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
|
||||
sqlite3_prepare_v2(ppDb, insert_statement.c_str(), insert_statement.length(), &stmt, NULL);
|
||||
|
||||
encryptedOk = true;
|
||||
|
||||
this->setInterval(15 * 1000);
|
||||
}
|
||||
|
||||
int32_t StoreForwardPlusPlusModule::runOnce()
|
||||
{
|
||||
LOG_WARN("StoreForward++ runONce");
|
||||
if (getRTCQuality() < RTCQualityNTP) {
|
||||
LOG_WARN("StoreForward++ deferred due to time quality %u", getRTCQuality());
|
||||
return 60 * 60 * 1000;
|
||||
}
|
||||
uint8_t root_hash_bytes[32] = {0};
|
||||
ChannelHash hash = channels.getHash(0);
|
||||
getOrAddRootFromChannelHash(hash, root_hash_bytes);
|
||||
|
||||
// get tip of chain for this channel
|
||||
uint8_t last_message_chain_hash[32] = {0};
|
||||
uint8_t last_message_hash[32] = {0};
|
||||
LOG_WARN("here5");
|
||||
|
||||
if (!getChainEnd(hash, last_message_chain_hash, last_message_hash)) {
|
||||
LOG_WARN("Store and Forward++ database lookup returned null");
|
||||
return 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
meshtastic_StoreForwardPlusPlus storeforward = meshtastic_StoreForwardPlusPlus_init_zero;
|
||||
storeforward.sfpp_message_type = meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE;
|
||||
// set root hash
|
||||
|
||||
// set message hash
|
||||
storeforward.message_hash.size = 32;
|
||||
memcpy(storeforward.message_hash.bytes, last_message_hash, 32);
|
||||
|
||||
// set chain hash
|
||||
storeforward.chain_hash.size = 32;
|
||||
memcpy(storeforward.chain_hash.bytes, last_message_chain_hash, 32);
|
||||
|
||||
// set root hash
|
||||
storeforward.root_hash.size = 32;
|
||||
memcpy(storeforward.root_hash.bytes, root_hash_bytes, 32);
|
||||
|
||||
// storeforward.
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(storeforward);
|
||||
p->to = NODENUM_BROADCAST;
|
||||
p->decoded.want_response = false;
|
||||
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
p->channel = 0;
|
||||
LOG_INFO("Send packet to mesh");
|
||||
service->sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
|
||||
return 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_StoreForwardPlusPlus *t)
|
||||
{
|
||||
LOG_WARN("in handleReceivedProtobuf");
|
||||
LOG_WARN("Sfp++ node %u is informing us of packet", mp.from);
|
||||
printBytes("chain_hash ", t->chain_hash.bytes, t->chain_hash.size);
|
||||
if (t->sfpp_message_type == meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE) {
|
||||
// check chain_hash.size
|
||||
|
||||
if (portduino_config.sfpp_stratum0) {
|
||||
LOG_WARN("Received a CANON_ANNOUNCE while stratum 0");
|
||||
} else {
|
||||
uint8_t tmp_root_hash_bytes[32] = {0};
|
||||
|
||||
LOG_WARN("Received a CANON_ANNOUNCE");
|
||||
if (getRootFromChannelHash(router->p_encrypted->channel, tmp_root_hash_bytes)) {
|
||||
// we found the hash, check if it's the right one
|
||||
if (memcmp(tmp_root_hash_bytes, t->root_hash.bytes, 32) != 0) {
|
||||
LOG_WARN("Found root hash, and it doesn't match!");
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// There's the possibility that
|
||||
addRootToMappings(router->p_encrypted->channel, t->root_hash.bytes);
|
||||
LOG_WARN("Adding root hash to mappings");
|
||||
}
|
||||
|
||||
// get tip of chain for this channel
|
||||
uint8_t last_message_chain_hash[32] = {0};
|
||||
uint8_t last_message_hash[32] = {0};
|
||||
|
||||
// get chain tip
|
||||
if (getChainEnd(router->p_encrypted->channel, last_message_chain_hash, last_message_hash)) {
|
||||
if (memcmp(last_message_chain_hash, t->chain_hash.bytes, 32) == 0) {
|
||||
LOG_WARN("End of chain matches!");
|
||||
} else
|
||||
("End of chain does not match!");
|
||||
} else {
|
||||
LOG_WARN("No Messages on this chain, request!");
|
||||
requestNextMessage(t->root_hash.bytes, t->root_hash.bytes);
|
||||
}
|
||||
|
||||
// compare to chain tip in incoming message
|
||||
|
||||
// if not found, request the next message
|
||||
}
|
||||
} else if (t->sfpp_message_type == meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_REQUEST) {
|
||||
uint8_t next_chain_hash[32] = {0};
|
||||
|
||||
LOG_WARN("Received link request");
|
||||
getNextHash(t->root_hash.bytes, t->chain_hash.bytes, next_chain_hash);
|
||||
printBytes("next chain hash: ", next_chain_hash, 32);
|
||||
|
||||
broadcastLink(next_chain_hash, t->root_hash.bytes);
|
||||
|
||||
// if root and chain hashes are the same, grab the first message on the chain
|
||||
// if different, get the message directly after.
|
||||
// check if the root
|
||||
|
||||
} else if (t->sfpp_message_type == meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE) {
|
||||
LOG_WARN("Link Provide received!");
|
||||
ChannelHash _channel_hash = getChannelHashFromRoot(t->root_hash.bytes);
|
||||
|
||||
addToChain(t->encapsulated_to, t->encapsulated_from, t->encapsulated_id, false, _channel_hash, t->message.bytes,
|
||||
t->message.size, t->message_hash.bytes, t->chain_hash.bytes, t->root_hash.bytes, t->encapsulated_rxtime, "",
|
||||
0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ProcessMessage StoreForwardPlusPlusModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
// To avoid terrible time problems, require NTP or GPS time
|
||||
if (getRTCQuality() < RTCQualityNTP) {
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
// the sender+destination pair is an interesting unique id (though ordering) (smaller one goes first?)
|
||||
// so messages with a unique pair become a chain
|
||||
// These get a table
|
||||
|
||||
// message to broadcast get a chain per channel hash
|
||||
// second table
|
||||
// for now, channel messages are limited to decryptable
|
||||
// limited to text messages
|
||||
|
||||
// create a unique-from-nodenums() class that returns a 64-bit value
|
||||
|
||||
SHA256 message_hash, chain_hash;
|
||||
uint8_t message_hash_bytes[32] = {0};
|
||||
uint8_t chain_hash_bytes[32] = {0};
|
||||
uint8_t root_hash_bytes[32] = {0};
|
||||
|
||||
// For the moment, this is strictly LoRa
|
||||
if (mp.transport_mechanism != meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA) {
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
// will eventually host DMs and other undecodable messages
|
||||
if (mp.which_payload_variant != meshtastic_MeshPacket_decoded_tag) {
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
// refuse without valid time?
|
||||
LOG_WARN("in handleReceived");
|
||||
if (mp.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP && mp.to == NODENUM_BROADCAST) {
|
||||
|
||||
// do not include rxtime in the message hash. We want these to match when more then one node receives and compares notes.
|
||||
// maybe include it in the commit hash
|
||||
|
||||
message_hash.reset();
|
||||
message_hash.update(router->p_encrypted->encrypted.bytes, router->p_encrypted->encrypted.size);
|
||||
message_hash.update(&mp.to, sizeof(mp.to));
|
||||
message_hash.update(&mp.from, sizeof(mp.from));
|
||||
message_hash.update(&mp.id, sizeof(mp.id));
|
||||
message_hash.finalize(message_hash_bytes, 32);
|
||||
|
||||
sqlite3_stmt *checkDup;
|
||||
sqlite3_prepare_v2(ppDb, "SELECT COUNT(*) from channel_messages where commit_hash=?", -1, &checkDup, NULL);
|
||||
sqlite3_bind_blob(checkDup, 1, message_hash_bytes, 32, NULL);
|
||||
sqlite3_step(checkDup);
|
||||
int numberFound = sqlite3_column_int(checkDup, 0);
|
||||
LOG_WARN("found %u times in db", numberFound);
|
||||
|
||||
if (numberFound != 0)
|
||||
return ProcessMessage::CONTINUE;
|
||||
|
||||
if (!portduino_config.sfpp_stratum0) {
|
||||
LOG_WARN("TODO: downstream collection of messages");
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
|
||||
// need to resolve the channel hash to the root hash
|
||||
getRootFromChannelHash(router->p_encrypted->channel, root_hash_bytes);
|
||||
|
||||
std::string getEntry_string =
|
||||
"select commit_hash from channel_messages where channel_hash=? order by rowid desc LIMIT 1;";
|
||||
sqlite3_stmt *getEntry;
|
||||
int rc = sqlite3_prepare_v2(ppDb, getEntry_string.c_str(), getEntry_string.size(), &getEntry, NULL);
|
||||
sqlite3_bind_int(getEntry, 1, router->p_encrypted->channel);
|
||||
sqlite3_step(getEntry);
|
||||
|
||||
// this is allocated by sqlite3 and will be deleted when finalize is called
|
||||
uint8_t *last_message_hash = (uint8_t *)sqlite3_column_blob(getEntry, 0);
|
||||
if (last_message_hash) {
|
||||
printBytes("last message: 0x", last_message_hash, 32);
|
||||
} else {
|
||||
printBytes("new chain root: 0x", root_hash_bytes, 32);
|
||||
}
|
||||
|
||||
// look for message_hash_bytes in db
|
||||
// if found, we bail early
|
||||
|
||||
chain_hash.reset();
|
||||
if (last_message_hash) {
|
||||
chain_hash.update(last_message_hash, 32);
|
||||
} else {
|
||||
chain_hash.update(root_hash_bytes, 32);
|
||||
}
|
||||
chain_hash.update(message_hash_bytes, 32);
|
||||
// message_hash.update(&mp.rx_time, sizeof(mp.rx_time));
|
||||
chain_hash.finalize(chain_hash_bytes, 32);
|
||||
|
||||
sqlite3_finalize(getEntry);
|
||||
|
||||
// select HEX(commit_hash),HEX(channel_hash), payload, destination from channel_messages order by rowid desc;
|
||||
|
||||
// push a message into the local chain DB
|
||||
|
||||
addToChain(mp.to, mp.from, mp.id, mp.want_ack, router->p_encrypted->channel, router->p_encrypted->encrypted.bytes,
|
||||
router->p_encrypted->encrypted.size, message_hash_bytes, chain_hash_bytes, root_hash_bytes, mp.rx_time,
|
||||
(char *)mp.decoded.payload.bytes, mp.decoded.payload.size);
|
||||
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
|
||||
// one of the command messages
|
||||
} else if (mp.decoded.portnum == meshtastic_PortNum_STORE_FORWARD_PLUSPLUS_APP) {
|
||||
LOG_WARN("Got a STORE_FORWARD++ packet");
|
||||
meshtastic_StoreForwardPlusPlus scratch;
|
||||
pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_StoreForwardPlusPlus_fields, &scratch);
|
||||
handleReceivedProtobuf(mp, &scratch);
|
||||
// when we get an update this way, if the message isn't on the chain, this node hasn't seen it, and can rebroadcast.
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::getRootFromChannelHash(ChannelHash _ch_hash, uint8_t *_root_hash)
|
||||
{
|
||||
bool found = false;
|
||||
sqlite3_stmt *getHash;
|
||||
int rc = sqlite3_prepare_v2(ppDb, "select root_hash from mappings where identifier=?;", -1, &getHash, NULL);
|
||||
sqlite3_bind_int(getHash, 1, _ch_hash);
|
||||
sqlite3_step(getHash);
|
||||
uint8_t *tmp_root_hash = (uint8_t *)sqlite3_column_blob(getHash, 0);
|
||||
if (tmp_root_hash) {
|
||||
LOG_WARN("Found root hash!");
|
||||
memcpy(_root_hash, tmp_root_hash, 32);
|
||||
found = true;
|
||||
}
|
||||
sqlite3_finalize(getHash);
|
||||
return found;
|
||||
}
|
||||
|
||||
ChannelHash StoreForwardPlusPlusModule::getChannelHashFromRoot(uint8_t *_root_hash)
|
||||
{
|
||||
sqlite3_stmt *getHash;
|
||||
int rc = sqlite3_prepare_v2(ppDb, "select identifier from mappings where root_hash=?;", -1, &getHash, NULL);
|
||||
sqlite3_bind_blob(getHash, 1, _root_hash, 32, NULL);
|
||||
sqlite3_step(getHash);
|
||||
ChannelHash tmp_hash = (ChannelHash)sqlite3_column_int(getHash, 0);
|
||||
sqlite3_finalize(getHash);
|
||||
return tmp_hash;
|
||||
}
|
||||
|
||||
// return code indicates newly created chain
|
||||
bool StoreForwardPlusPlusModule::getOrAddRootFromChannelHash(ChannelHash _ch_hash, uint8_t *_root_hash)
|
||||
{
|
||||
LOG_WARN("getOrAddRootFromChannelHash()");
|
||||
bool isNew = !getRootFromChannelHash(_ch_hash, _root_hash);
|
||||
|
||||
if (isNew) {
|
||||
if (portduino_config.sfpp_stratum0) {
|
||||
LOG_WARN("Generating Root hash!");
|
||||
// generate root hash
|
||||
SHA256 chain_hash;
|
||||
chain_hash.update(&_ch_hash, sizeof(_ch_hash));
|
||||
NodeNum ourNode = nodeDB->getNodeNum();
|
||||
chain_hash.update(&ourNode, sizeof(ourNode));
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true);
|
||||
chain_hash.update(&rtc_sec, sizeof(rtc_sec));
|
||||
chain_hash.finalize(_root_hash, 32);
|
||||
|
||||
addRootToMappings(_ch_hash, _root_hash);
|
||||
LOG_WARN("here4");
|
||||
}
|
||||
}
|
||||
return isNew;
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::addRootToMappings(ChannelHash _ch_hash, uint8_t *_root_hash)
|
||||
{
|
||||
LOG_WARN("addRootToMappings()");
|
||||
printBytes("_root_hash", _root_hash, 32);
|
||||
sqlite3_stmt *getHash;
|
||||
|
||||
// write to the table
|
||||
int rc =
|
||||
sqlite3_prepare_v2(ppDb, "INSERT INTO mappings (chain_type, identifier, root_hash) VALUES(?, ?, ?);", -1, &getHash, NULL);
|
||||
LOG_WARN("%d", rc);
|
||||
int type = chain_types::channel_chain;
|
||||
// note, must be an int variable
|
||||
|
||||
sqlite3_bind_int(getHash, 1, type);
|
||||
sqlite3_bind_int(getHash, 2, _ch_hash);
|
||||
sqlite3_bind_blob(getHash, 3, _root_hash, 32, NULL);
|
||||
LOG_WARN("here1");
|
||||
// sqlite3_bind_int(getHash, 4, nodeToAdd);
|
||||
rc = sqlite3_step(getHash);
|
||||
LOG_WARN("here2 %u, %s", rc, sqlite3_errmsg(ppDb));
|
||||
sqlite3_finalize(getHash);
|
||||
LOG_WARN("here3");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::getChainEnd(ChannelHash _ch_hash, uint8_t *_chain_hash, uint8_t *_message_hash)
|
||||
{
|
||||
LOG_WARN("getChainEnd");
|
||||
|
||||
std::string getEntry_string =
|
||||
"select commit_hash, message_hash from channel_messages where channel_hash=? order by rowid desc LIMIT 1;";
|
||||
sqlite3_stmt *getEntry;
|
||||
int rc = sqlite3_prepare_v2(ppDb, getEntry_string.c_str(), getEntry_string.size(), &getEntry, NULL);
|
||||
sqlite3_bind_int(getEntry, 1, _ch_hash);
|
||||
sqlite3_step(getEntry);
|
||||
uint8_t *last_message_chain_hash = (uint8_t *)sqlite3_column_blob(getEntry, 0);
|
||||
uint8_t *last_message_hash = (uint8_t *)sqlite3_column_blob(getEntry, 1);
|
||||
|
||||
if (last_message_chain_hash == nullptr || last_message_hash == nullptr) {
|
||||
LOG_WARN("Store and Forward++ database lookup returned null");
|
||||
sqlite3_finalize(getEntry);
|
||||
|
||||
return false;
|
||||
}
|
||||
memcpy(_chain_hash, last_message_chain_hash, 32);
|
||||
memcpy(_message_hash, last_message_hash, 32);
|
||||
sqlite3_finalize(getEntry);
|
||||
return true;
|
||||
}
|
||||
|
||||
void StoreForwardPlusPlusModule::requestNextMessage(uint8_t *_root_hash, uint8_t *_chain_hash)
|
||||
{
|
||||
|
||||
meshtastic_StoreForwardPlusPlus storeforward = meshtastic_StoreForwardPlusPlus_init_zero;
|
||||
storeforward.sfpp_message_type = meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_REQUEST;
|
||||
// set root hash
|
||||
|
||||
// set chain hash
|
||||
storeforward.chain_hash.size = 32;
|
||||
memcpy(storeforward.chain_hash.bytes, _chain_hash, 32);
|
||||
|
||||
// set root hash
|
||||
storeforward.root_hash.size = 32;
|
||||
memcpy(storeforward.root_hash.bytes, _root_hash, 32);
|
||||
|
||||
// storeforward.
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(storeforward);
|
||||
p->to = NODENUM_BROADCAST;
|
||||
p->decoded.want_response = false;
|
||||
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
p->channel = 0;
|
||||
LOG_INFO("Send packet to mesh");
|
||||
service->sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::getNextHash(uint8_t *_root_hash, uint8_t *_chain_hash, uint8_t *next_chain_hash)
|
||||
{
|
||||
LOG_WARN("getNextHash");
|
||||
|
||||
ChannelHash _channel_hash = getChannelHashFromRoot(_root_hash);
|
||||
LOG_WARN("_channel_hash %u", _channel_hash);
|
||||
|
||||
sqlite3_stmt *getHash;
|
||||
int rc = sqlite3_prepare_v2(ppDb, "select commit_hash from channel_messages where channel_hash=? order by rowid ASC;", -1,
|
||||
&getHash, NULL);
|
||||
|
||||
LOG_WARN("%d", rc);
|
||||
if (rc != SQLITE_OK) {
|
||||
LOG_WARN("here2 %u, %s", rc, sqlite3_errmsg(ppDb));
|
||||
}
|
||||
sqlite3_bind_int(getHash, 1, _channel_hash);
|
||||
sqlite3_step(getHash);
|
||||
bool found_hash = false;
|
||||
|
||||
// asking for the first entry on the chain
|
||||
if (memcmp(_root_hash, _chain_hash, 32) == 0) {
|
||||
uint8_t *tmp_chain_hash = (uint8_t *)sqlite3_column_blob(getHash, 0);
|
||||
memcpy(next_chain_hash, tmp_chain_hash, 32);
|
||||
found_hash = true;
|
||||
} else {
|
||||
uint8_t *tmp_chain_hash;
|
||||
while (sqlite3_step(getHash) != SQLITE_DONE) {
|
||||
tmp_chain_hash = (uint8_t *)sqlite3_column_blob(getHash, 0);
|
||||
if (found_hash) {
|
||||
memcpy(next_chain_hash, tmp_chain_hash, 32);
|
||||
break;
|
||||
}
|
||||
if (memcmp(tmp_chain_hash, _chain_hash, 32) == 0)
|
||||
found_hash = true;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_finalize(getHash);
|
||||
return found_hash;
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::broadcastLink(uint8_t *_chain_hash, uint8_t *_root_hash)
|
||||
{
|
||||
sqlite3_stmt *getHash;
|
||||
int rc = sqlite3_prepare_v2(ppDb, "select destination, sender, packet_id, encrypted_bytes, message_hash, rx_time \
|
||||
from channel_messages where commit_hash=?;",
|
||||
-1, &getHash, NULL);
|
||||
|
||||
LOG_WARN("%d", rc);
|
||||
if (rc != SQLITE_OK) {
|
||||
LOG_WARN("here2 %u, %s", rc, sqlite3_errmsg(ppDb));
|
||||
}
|
||||
sqlite3_bind_blob(getHash, 1, _chain_hash, 32, NULL);
|
||||
sqlite3_step(getHash);
|
||||
|
||||
meshtastic_StoreForwardPlusPlus storeforward = meshtastic_StoreForwardPlusPlus_init_zero;
|
||||
storeforward.sfpp_message_type = meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE;
|
||||
|
||||
storeforward.encapsulated_to = sqlite3_column_int(getHash, 0);
|
||||
storeforward.encapsulated_from = sqlite3_column_int(getHash, 1);
|
||||
storeforward.encapsulated_id = sqlite3_column_int(getHash, 2);
|
||||
|
||||
uint8_t *_payload = (uint8_t *)sqlite3_column_blob(getHash, 3);
|
||||
storeforward.message.size = sqlite3_column_bytes(getHash, 3);
|
||||
memcpy(storeforward.message.bytes, _payload, storeforward.message.size);
|
||||
|
||||
uint8_t *_message_hash = (uint8_t *)sqlite3_column_blob(getHash, 4);
|
||||
storeforward.message_hash.size = 32;
|
||||
memcpy(storeforward.message_hash.bytes, _message_hash, storeforward.message_hash.size);
|
||||
|
||||
storeforward.encapsulated_rxtime = sqlite3_column_int(getHash, 5);
|
||||
|
||||
storeforward.chain_hash.size = 32;
|
||||
memcpy(storeforward.chain_hash.bytes, _chain_hash, 32);
|
||||
|
||||
storeforward.root_hash.size = 32;
|
||||
memcpy(storeforward.root_hash.bytes, _root_hash, 32);
|
||||
|
||||
sqlite3_finalize(getHash);
|
||||
|
||||
meshtastic_MeshPacket *p = allocDataProtobuf(storeforward);
|
||||
p->to = NODENUM_BROADCAST;
|
||||
p->decoded.want_response = false;
|
||||
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
p->channel = 0;
|
||||
LOG_INFO("Send link to mesh");
|
||||
service->sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StoreForwardPlusPlusModule::addToChain(uint32_t to, uint32_t from, uint32_t id, bool want_ack, ChannelHash channel_hash,
|
||||
uint8_t *encrypted_bytes, size_t encrypted_len, uint8_t *_message_hash,
|
||||
uint8_t *_chain_hash, uint8_t *_root_hash, uint32_t _rx_time, char *payload_bytes,
|
||||
size_t payload_len)
|
||||
|
||||
{
|
||||
// push a message into the local chain DB
|
||||
// destination
|
||||
sqlite3_bind_int(stmt, 1, to);
|
||||
// sender
|
||||
sqlite3_bind_int(stmt, 2, from);
|
||||
// packet_id
|
||||
sqlite3_bind_int(stmt, 3, id);
|
||||
// want_ack
|
||||
sqlite3_bind_int(stmt, 4, want_ack);
|
||||
// channel_hash
|
||||
sqlite3_bind_int(stmt, 5, channel_hash);
|
||||
// encrypted_bytes
|
||||
sqlite3_bind_blob(stmt, 6, encrypted_bytes, encrypted_len, NULL);
|
||||
|
||||
// message_hash
|
||||
sqlite3_bind_blob(stmt, 7, _message_hash, 32, NULL);
|
||||
// rx_time
|
||||
sqlite3_bind_int(stmt, 8, _rx_time);
|
||||
|
||||
// commit_hash
|
||||
sqlite3_bind_blob(stmt, 9, _chain_hash, 32, NULL);
|
||||
// payload
|
||||
sqlite3_bind_text(stmt, 10, payload_bytes, payload_len, NULL);
|
||||
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_reset(stmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
// announce latest hash
|
||||
// chain_end_announce
|
||||
|
||||
// check if hash is known
|
||||
// hash_query
|
||||
|
||||
// request next message
|
||||
// link_request
|
||||
|
||||
// send encapsulated message
|
||||
// link_provide_whole
|
||||
// link_provide_half1
|
||||
// link_provide_half2
|
||||
|
||||
// onboard request message?
|
||||
|
||||
// get x from top?
|
||||
|
||||
// messages
|
||||
// Given this chain root, do you have a packet that matches this message hash?
|
||||
// responds with chain hash etc
|
||||
|
||||
// given this chain root, what is your last chain and message hash?
|
||||
// given this chain root, what is your next message after this chain hash? (do we have an overhead problem here?) (blegh,
|
||||
// fragmentation) (but also, trunking)
|
||||
|
||||
// broadcast on this chain root, here is my last chain hash
|
||||
|
||||
// consider third-order nodes
|
||||
|
||||
// I can't talk directly to strata, I can talk to a satellite. Inform sat of a message. Sat stores it as if had seen it locally,
|
||||
// and pushes it to central
|
||||
|
||||
// message Eventually works out through chain
|
||||
|
||||
// sat can capture time of receipt
|
||||
|
||||
// terms:
|
||||
// CANON
|
||||
// stratum
|
||||
// chain
|
||||
// links on the chain
|
||||
@@ -1,74 +0,0 @@
|
||||
#pragma once
|
||||
#include "Channels.h"
|
||||
#include "ProtobufModule.h"
|
||||
#include "Router.h"
|
||||
#include "SinglePortModule.h"
|
||||
#include "sqlite3.h"
|
||||
|
||||
/**
|
||||
* A simple example module that just replies with "Message received" to any message it receives.
|
||||
*/
|
||||
class StoreForwardPlusPlusModule : public ProtobufModule<meshtastic_StoreForwardPlusPlus>, private concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
StoreForwardPlusPlusModule();
|
||||
|
||||
/*
|
||||
-Override the wantPacket method.
|
||||
*/
|
||||
virtual bool wantPacket(const meshtastic_MeshPacket *p) override
|
||||
{
|
||||
// if encrypted but not too FFFF
|
||||
// want
|
||||
switch (p->decoded.portnum) {
|
||||
case meshtastic_PortNum_TEXT_MESSAGE_APP:
|
||||
case 35:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/** 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;
|
||||
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_StoreForwardPlusPlus *t) override;
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
private:
|
||||
sqlite3 *ppDb;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
// returns wasfound
|
||||
bool getRootFromChannelHash(ChannelHash, uint8_t *);
|
||||
|
||||
ChannelHash getChannelHashFromRoot(uint8_t *_root_hash);
|
||||
|
||||
bool getNextHash(uint8_t *_root_hash, uint8_t *_chain_hash, uint8_t *next_chain_hash);
|
||||
|
||||
// returns isnew
|
||||
bool getOrAddRootFromChannelHash(ChannelHash, uint8_t *);
|
||||
|
||||
bool addRootToMappings(ChannelHash, uint8_t *);
|
||||
|
||||
// return indicates message found
|
||||
bool getChainEnd(ChannelHash, uint8_t *, uint8_t *);
|
||||
|
||||
void requestNextMessage(uint8_t *, uint8_t *);
|
||||
|
||||
bool broadcastLink(uint8_t *_chain_hash, uint8_t *_root_hash);
|
||||
|
||||
bool addToChain(uint32_t, uint32_t, uint32_t, bool, ChannelHash, uint8_t *, size_t, uint8_t *, uint8_t *, uint8_t *, uint32_t,
|
||||
char *, size_t);
|
||||
|
||||
enum chain_types {
|
||||
channel_chain = 0,
|
||||
};
|
||||
};
|
||||
@@ -1,235 +0,0 @@
|
||||
// create second module for satellites?
|
||||
|
||||
// The central node will generate a 256 or 128 bit value as its seed. This is the value other nodes subscribe to, and serves as
|
||||
// the root of the chain
|
||||
|
||||
//
|
||||
|
||||
// Basic design:
|
||||
// This module watches a channel for text messages.
|
||||
// each message gets sha256 summed, and then appended to a git-style blockchain. Probably need a counter, too
|
||||
// then the message, metadata, hash, and git hash information are saved. sqlite?
|
||||
|
||||
// nodes/sub-controllers can subscribe to a database
|
||||
|
||||
// A node can DM the controller, querying if a single message is on the chain, or asking for the last message hash
|
||||
|
||||
// if the message is not on the chain, the node can resend the message
|
||||
|
||||
// if the node lacks messages, it can request them
|
||||
|
||||
// will need the concept of sub-controllers, that subscribe to the central controller, can help push updates
|
||||
|
||||
// catch-up messages only go out when the mesh is low use %
|
||||
|
||||
// Normal firmware will only attempt to sync the chain a few times, then just ask for the latest few messages. A phone app can try
|
||||
// harder
|
||||
|
||||
// host will periodically advertise its presence
|
||||
|
||||
// at least initially, there can only be one authoritative host
|
||||
|
||||
// first draft is just to save channel 0 in a git-style database
|
||||
|
||||
// message objects get a hash value
|
||||
// the message chain gets a commit hash
|
||||
//
|
||||
|
||||
#include "StoreForwardPlusPlusSat.h"
|
||||
#include "SHA256.h"
|
||||
#include "meshUtils.h"
|
||||
|
||||
StoreForwardPlusPlusSatModule::StoreForwardPlusPlusSatModule() : SinglePortModule("StoreForwardPlusPlus", (_meshtastic_PortNum)35)
|
||||
{
|
||||
LOG_WARN("StoreForwardPlusPlusSatModule init");
|
||||
int res = sqlite3_open("test.db", &ppDb);
|
||||
LOG_WARN("Result1 %u", res);
|
||||
char *err = nullptr;
|
||||
res = sqlite3_exec(ppDb, " \
|
||||
CREATE TABLE channel_messages( \
|
||||
destination INT NOT NULL, \
|
||||
sender INT NOT NULL, \
|
||||
packet_id INT NOT NULL, \
|
||||
want_ack BOOL NOT NULL, \
|
||||
channel_hash INT NOT NULL, \
|
||||
encrypted_bytes BLOB NOT NULL, \
|
||||
message_hash BLOB NOT NULL, \
|
||||
rx_time INT NOT NULL, \
|
||||
commit_hash BLOB NOT NULL, \
|
||||
payload TEXT, \
|
||||
PRIMARY KEY (message_hash) \
|
||||
);",
|
||||
NULL, NULL, &err);
|
||||
LOG_WARN("Result2 %u", res);
|
||||
if (err != nullptr)
|
||||
;
|
||||
LOG_ERROR("%s", err);
|
||||
sqlite3_free(err);
|
||||
|
||||
// create table DMs
|
||||
res = sqlite3_exec(ppDb, " \
|
||||
CREATE TABLE direct_messages( \
|
||||
destination INT NOT NULL, \
|
||||
sender INT NOT NULL, \
|
||||
packet_id INT NOT NULL, \
|
||||
want_ack BOOL NOT NULL, \
|
||||
channel_hash INT NOT NULL, \
|
||||
commit_hash BLOB NOT NULL, \
|
||||
encrypted_bytes BLOB NOT NULL, \
|
||||
message_hash BLOB NOT NULL, \
|
||||
payload TEXT, \
|
||||
rx_time INT NOT NULL, \
|
||||
PRIMARY KEY (message_hash) \
|
||||
);",
|
||||
NULL, NULL, &err);
|
||||
LOG_WARN("Result2 %u", res);
|
||||
if (err != nullptr)
|
||||
;
|
||||
LOG_ERROR("%s", err);
|
||||
sqlite3_free(err);
|
||||
|
||||
// create table mappings
|
||||
// create table DMs
|
||||
res = sqlite3_exec(ppDb, " \
|
||||
CREATE TABLE mappings( \
|
||||
chain_type INT NOT NULL, \
|
||||
identifier INT NOT NULL, \
|
||||
root_hash BLOB NOT NULL, \
|
||||
PRIMARY KEY (identifier) \
|
||||
);",
|
||||
NULL, NULL, &err);
|
||||
LOG_WARN("Result2 %u", res);
|
||||
if (err != nullptr)
|
||||
;
|
||||
LOG_ERROR("%s", err);
|
||||
sqlite3_free(err);
|
||||
// type
|
||||
// sha256hash
|
||||
// channelhash or 64 bit combination
|
||||
// The sat version needs a scratch database of messages that have not been checked in
|
||||
|
||||
// store schema version somewhere
|
||||
|
||||
std::string insert_statement = "INSERT INTO channel_messages (destination, sender, packet_id, want_ack, channel_hash, \
|
||||
encrypted_bytes, message_hash, rx_time, commit_hash, payload) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
|
||||
sqlite3_prepare(ppDb, insert_statement.c_str(), insert_statement.length(), &stmt, NULL);
|
||||
|
||||
encryptedOk = true;
|
||||
}
|
||||
|
||||
ProcessMessage StoreForwardPlusPlusSatModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||
{
|
||||
|
||||
// the sender+destination pair is an interesting unique id (though ordering) (smaller one goes first?)
|
||||
// so messages with a unique pair become a chain
|
||||
// These get a table
|
||||
|
||||
// message to broadcast get a chain per channel hash
|
||||
// second table
|
||||
// for now, channel messages are limited to decryptable
|
||||
// limited to text messages
|
||||
|
||||
// create a unique-from-nodenums() class that returns a 64-bit value
|
||||
|
||||
SHA256 message_hash, chain_hash;
|
||||
uint8_t message_hash_bytes[32] = {0};
|
||||
uint8_t chain_hash_bytes[32] = {0};
|
||||
|
||||
// For the moment, this is strictly LoRa
|
||||
if (mp.transport_mechanism != meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA) {
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
// will eventually host DMs and other undecodable messages
|
||||
if (mp.which_payload_variant != meshtastic_MeshPacket_decoded_tag) {
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
// refuse without valid time?
|
||||
LOG_WARN("in handleReceived");
|
||||
std::string getEntry_string = "select commit_hash from channel_messages where channel_hash=? order by rowid desc LIMIT 1;";
|
||||
sqlite3_stmt *getEntry;
|
||||
int rc = sqlite3_prepare(ppDb, getEntry_string.c_str(), getEntry_string.size(), &getEntry, NULL);
|
||||
sqlite3_bind_int(getEntry, 1, router->p_encrypted->channel);
|
||||
sqlite3_step(getEntry);
|
||||
|
||||
// this is allocated by sqlite3 and will be deleted when finalize is called
|
||||
uint8_t *last_message_hash = (uint8_t *)sqlite3_column_blob(getEntry, 0);
|
||||
if (last_message_hash) {
|
||||
printBytes("last message: 0x", last_message_hash, 32);
|
||||
} else {
|
||||
// generate root hash and populate lookup table
|
||||
}
|
||||
|
||||
// do not include rxtime in the message hash. We want these to match when more then one node receives and compares notes.
|
||||
// feel free to include it in the commit hash
|
||||
|
||||
message_hash.reset();
|
||||
message_hash.update(router->p_encrypted->encrypted.bytes, router->p_encrypted->encrypted.size);
|
||||
message_hash.update(&mp.to, sizeof(mp.to));
|
||||
message_hash.update(&mp.from, sizeof(mp.from));
|
||||
message_hash.update(&mp.id, sizeof(mp.id));
|
||||
message_hash.finalize(message_hash_bytes, 32);
|
||||
|
||||
chain_hash.reset();
|
||||
if (last_message_hash) {
|
||||
chain_hash.update(last_message_hash, 32);
|
||||
}
|
||||
chain_hash.update(message_hash_bytes, 32);
|
||||
// message_hash.update(&mp.rx_time, sizeof(mp.rx_time));
|
||||
chain_hash.finalize(chain_hash_bytes, 32);
|
||||
|
||||
sqlite3_finalize(getEntry);
|
||||
|
||||
// select HEX(commit_hash),HEX(channel_hash), payload, destination from channel_messages order by rowid desc;
|
||||
|
||||
// push a message into the local chain DB
|
||||
// destination
|
||||
sqlite3_bind_int(stmt, 1, mp.to);
|
||||
// sender
|
||||
sqlite3_bind_int(stmt, 2, mp.from);
|
||||
// packet_id
|
||||
sqlite3_bind_int(stmt, 3, mp.id);
|
||||
// want_ack
|
||||
sqlite3_bind_int(stmt, 4, mp.want_ack);
|
||||
// channel_hash
|
||||
sqlite3_bind_int(stmt, 5, router->p_encrypted->channel);
|
||||
// encrypted_bytes
|
||||
sqlite3_bind_blob(stmt, 6, router->p_encrypted->encrypted.bytes, router->p_encrypted->encrypted.size, NULL);
|
||||
|
||||
// message_hash
|
||||
sqlite3_bind_blob(stmt, 7, message_hash_bytes, 32, NULL);
|
||||
// rx_time
|
||||
sqlite3_bind_int(stmt, 8, mp.rx_time);
|
||||
|
||||
// commit_hash
|
||||
sqlite3_bind_blob(stmt, 9, chain_hash_bytes, 32, NULL);
|
||||
// payload
|
||||
sqlite3_bind_text(stmt, 10, (char *)mp.decoded.payload.bytes, mp.decoded.payload.size, NULL);
|
||||
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_reset(stmt);
|
||||
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
|
||||
// when we get an update this way, if the message isn't on the chain or in the scratch table, this node hasn't seen it, and can
|
||||
// rebroadcast.
|
||||
|
||||
// messages
|
||||
// Given this chain root, do you have a packet that matches this message hash?
|
||||
// responds with chain hash etc
|
||||
|
||||
// given this chain root, what is your last chain and message hash?
|
||||
// given this chain root, what is your next message after this chain hash? (do we have an overhead problem here?) (blegh,
|
||||
// fragmentation) (but also, trunking)
|
||||
|
||||
// broadcast on this chain root, here is my last chain hash
|
||||
|
||||
// consider third-order nodes
|
||||
|
||||
// I can't talk directly to strata, I can talk to a satellite. Inform sat of a message. Sat stores it as if had seen it locally,
|
||||
// and pushes it to central
|
||||
|
||||
// message Eventually works out through chain
|
||||
|
||||
// sat can capture time of receipt
|
||||
@@ -1,41 +0,0 @@
|
||||
#pragma once
|
||||
#include "Router.h"
|
||||
#include "SinglePortModule.h"
|
||||
#include "sqlite3.h"
|
||||
|
||||
/**
|
||||
* A simple example module that just replies with "Message received" to any message it receives.
|
||||
*/
|
||||
class StoreForwardPlusPlusSatModule : public SinglePortModule // should probably derive this from the main class
|
||||
{
|
||||
public:
|
||||
/** Constructor
|
||||
* name is for debugging output
|
||||
*/
|
||||
StoreForwardPlusPlusSatModule();
|
||||
|
||||
/*
|
||||
-Override the wantPacket method.
|
||||
*/
|
||||
virtual bool wantPacket(const meshtastic_MeshPacket *p) override
|
||||
{
|
||||
switch (p->decoded.portnum) {
|
||||
case meshtastic_PortNum_TEXT_MESSAGE_APP:
|
||||
case 35:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/** 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;
|
||||
|
||||
private:
|
||||
sqlite3 *ppDb;
|
||||
sqlite3_stmt *stmt;
|
||||
};
|
||||
@@ -45,12 +45,8 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
|
||||
{
|
||||
auto p = *pptr;
|
||||
|
||||
const auto transport = mp.transport_mechanism;
|
||||
if (isFromUs(&mp) && !IS_ONE_OF(transport, meshtastic_MeshPacket_TransportMechanism_TRANSPORT_INTERNAL,
|
||||
meshtastic_MeshPacket_TransportMechanism_TRANSPORT_API)) {
|
||||
LOG_WARN("Ignoring packet supposedly from us over external transport");
|
||||
return true;
|
||||
}
|
||||
// If inbound message is a replay (or spoof!) of our own messages, we shouldn't process
|
||||
// (why use second-hand sources for our own data?)
|
||||
|
||||
// FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER)
|
||||
// to set fixed location, EUD-GPS location or just the time (see also issue #900)
|
||||
@@ -476,53 +472,19 @@ void PositionModule::sendLostAndFoundText()
|
||||
delete[] message;
|
||||
}
|
||||
|
||||
// Helper: return imprecise (truncated + centered) lat/lon as int32 using current precision
|
||||
static inline void computeImpreciseLatLon(int32_t inLat, int32_t inLon, uint8_t precisionBits, int32_t &outLat, int32_t &outLon)
|
||||
{
|
||||
if (precisionBits > 0 && precisionBits < 32) {
|
||||
// Build mask for top 'precisionBits' bits of a 32-bit unsigned field
|
||||
const uint32_t mask = (precisionBits == 32) ? UINT32_MAX : (UINT32_MAX << (32 - precisionBits));
|
||||
// Note: latitude_i/longitude_i are stored as signed 32-bit in meshtastic code but
|
||||
// the bitmask logic used previously operated as unsigned—preserve that behavior by
|
||||
// casting to uint32_t for masking, then back to int32_t.
|
||||
uint32_t lat_u = static_cast<uint32_t>(inLat) & mask;
|
||||
uint32_t lon_u = static_cast<uint32_t>(inLon) & mask;
|
||||
|
||||
// Add the "center of cell" offset used elsewhere:
|
||||
// The code previously added (1 << (31 - precision)) to produce the middle of the possible location.
|
||||
uint32_t center_offset = (1u << (31 - precisionBits));
|
||||
lat_u += center_offset;
|
||||
lon_u += center_offset;
|
||||
|
||||
outLat = static_cast<int32_t>(lat_u);
|
||||
outLon = static_cast<int32_t>(lon_u);
|
||||
} else {
|
||||
// full precision: return input unchanged
|
||||
outLat = inLat;
|
||||
outLon = inLon;
|
||||
}
|
||||
}
|
||||
|
||||
struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition)
|
||||
{
|
||||
// The minimum distance to travel before we are able to send a new position packet.
|
||||
const uint32_t distanceTravelThreshold =
|
||||
Default::getConfiguredOrDefault(config.position.broadcast_smart_minimum_distance, 100);
|
||||
|
||||
int32_t lastLatImprecise, lastLonImprecise;
|
||||
int32_t currentLatImprecise, currentLonImprecise;
|
||||
// Determine the distance in meters between two points on the globe
|
||||
float distanceTraveledSinceLastSend = GeoCoord::latLongToMeter(
|
||||
lastGpsLatitude * 1e-7, lastGpsLongitude * 1e-7, currentPosition.latitude_i * 1e-7, currentPosition.longitude_i * 1e-7);
|
||||
|
||||
computeImpreciseLatLon(lastGpsLatitude, lastGpsLongitude, precision, lastLatImprecise, lastLonImprecise);
|
||||
computeImpreciseLatLon(currentPosition.latitude_i, currentPosition.longitude_i, precision, currentLatImprecise,
|
||||
currentLonImprecise);
|
||||
|
||||
float distMeters = GeoCoord::latLongToMeter(lastLatImprecise * 1e-7, lastLonImprecise * 1e-7, currentLatImprecise * 1e-7,
|
||||
currentLonImprecise * 1e-7);
|
||||
|
||||
float distanceTraveled = fabsf(distMeters);
|
||||
|
||||
return SmartPosition{.distanceTraveled = distanceTraveled,
|
||||
return SmartPosition{.distanceTraveled = abs(distanceTraveledSinceLastSend),
|
||||
.distanceThreshold = distanceTravelThreshold,
|
||||
.hasTraveledOverThreshold = distanceTraveled >= distanceTravelThreshold};
|
||||
.hasTraveledOverThreshold = abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold};
|
||||
}
|
||||
|
||||
void PositionModule::handleNewPosition()
|
||||
|
||||
@@ -75,12 +75,6 @@ uint8_t RoutingModule::getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit
|
||||
return Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit); // Use the default hop limit
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket *RoutingModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
||||
uint8_t hopLimit)
|
||||
{
|
||||
return MeshModule::allocAckNak(err, to, idFrom, chIndex, hopLimit);
|
||||
}
|
||||
|
||||
RoutingModule::RoutingModule() : ProtobufModule("routing", meshtastic_PortNum_ROUTING_APP, &meshtastic_Routing_msg)
|
||||
{
|
||||
isPromiscuous = true;
|
||||
|
||||
@@ -16,9 +16,6 @@ class RoutingModule : public ProtobufModule<meshtastic_Routing>
|
||||
virtual void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0,
|
||||
bool ackWantsAck = false);
|
||||
|
||||
meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
||||
uint8_t hopLimit = 0);
|
||||
|
||||
// Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response
|
||||
uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit);
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial
|
||||
api_type = TYPE_SERIAL;
|
||||
}
|
||||
static Print *serialPrint = &Serial;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172) || defined(EBYTE_E77_MBL)
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172) || defined(EBYTE_E77_MBL) || defined(CONFIG_IDF_TARGET_ESP32H2)
|
||||
SerialModule::SerialModule() : StreamAPI(&Serial1), concurrency::OSThread("Serial")
|
||||
{
|
||||
api_type = TYPE_SERIAL;
|
||||
@@ -175,7 +175,7 @@ int32_t SerialModule::runOnce()
|
||||
// Give it a chance to flush out 💩
|
||||
delay(10);
|
||||
}
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2)
|
||||
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
|
||||
Serial1.setRxBufferSize(RX_BUFFER);
|
||||
Serial1.begin(baud, SERIAL_8N1, moduleConfig.serial.rxd, moduleConfig.serial.txd);
|
||||
@@ -277,7 +277,7 @@ int32_t SerialModule::runOnce()
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2)
|
||||
while (Serial1.available()) {
|
||||
serialPayloadSize = Serial1.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||
#else
|
||||
@@ -538,7 +538,7 @@ void SerialModule::processWXSerial()
|
||||
{
|
||||
#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \
|
||||
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && \
|
||||
!defined(ARCH_STM32WL) && !defined(MUZI_BASE)
|
||||
!defined(ARCH_STM32WL) && !defined(MUZI_BASE) && !defined(CONFIG_IDF_TARGET_ESP32H2)
|
||||
static unsigned int lastAveraged = 0;
|
||||
static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded.
|
||||
static double dir_sum_sin = 0;
|
||||
|
||||
@@ -87,13 +87,10 @@ inline void onReceiveProto(char *topic, byte *payload, size_t length)
|
||||
// Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message.
|
||||
// We do this because packets are not rebroadcasted back into MQTT anymore and we assume that at least one node
|
||||
// receives it when we get our own packet back. Then we'll stop our retransmissions.
|
||||
if (isFromUs(e.packet)) {
|
||||
auto pAck = routingModule->allocAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index);
|
||||
pAck->transport_mechanism = meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MQTT;
|
||||
router->sendLocal(pAck);
|
||||
} else {
|
||||
if (isFromUs(e.packet))
|
||||
routingModule->sendAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index);
|
||||
else
|
||||
LOG_INFO("Ignore downlink message we originally sent");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isFromUs(e.packet)) {
|
||||
|
||||
@@ -169,6 +169,8 @@ void esp32Setup()
|
||||
// #define APP_WATCHDOG_SECS 45
|
||||
#define APP_WATCHDOG_SECS 90
|
||||
|
||||
// esp_task_wdt_init returns an unknown error, so skip it on ESP32H2
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||
esp_task_wdt_config_t *wdt_config = (esp_task_wdt_config_t *)malloc(sizeof(esp_task_wdt_config_t));
|
||||
wdt_config->timeout_ms = APP_WATCHDOG_SECS * 1000;
|
||||
@@ -181,7 +183,7 @@ void esp32Setup()
|
||||
#endif
|
||||
res = esp_task_wdt_add(NULL);
|
||||
assert(res == ESP_OK);
|
||||
|
||||
#endif
|
||||
#if HAS_32768HZ
|
||||
enableSlowCLK();
|
||||
#endif
|
||||
@@ -223,9 +225,10 @@ void cpuDeepSleep(uint32_t msecToWake)
|
||||
13,
|
||||
#endif
|
||||
34, 35, 37};
|
||||
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32H2
|
||||
for (int i = 0; i < sizeof(rtcGpios); i++)
|
||||
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// FIXME, disable internal rtc pullups/pulldowns on the non isolated pins. for inputs that we aren't using
|
||||
@@ -258,10 +261,10 @@ void cpuDeepSleep(uint32_t msecToWake)
|
||||
|
||||
#endif // #end ESP32S3_WAKE_TYPE
|
||||
#endif
|
||||
|
||||
#ifdef ESP_PD_DOMAIN_RTC_PERIPH
|
||||
// We want RTC peripherals to stay on
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
#endif
|
||||
esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
|
||||
esp_deep_sleep_start(); // TBD mA sleep current (battery)
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ void cpuDeepSleep(uint32_t msecToWake)
|
||||
#endif
|
||||
|
||||
#ifdef TTGO_T_ECHO
|
||||
// To power off the T-Echo, the display must be set
|
||||
// To power off the T-Echo, the display must be set
|
||||
// as an input pin; otherwise, there will be leakage current.
|
||||
pinMode(PIN_EINK_CS, INPUT);
|
||||
pinMode(PIN_EINK_DC, INPUT);
|
||||
|
||||
@@ -746,10 +746,6 @@ bool loadConfig(const char *configPath)
|
||||
}
|
||||
}
|
||||
|
||||
if (yamlConfig["StoreAndForward"]) {
|
||||
portduino_config.sfpp_stratum0 = (yamlConfig["StoreAndForward"]["Stratum0"]).as<bool>(false);
|
||||
}
|
||||
|
||||
if (yamlConfig["General"]) {
|
||||
portduino_config.MaxNodes = (yamlConfig["General"]["MaxNodes"]).as<int>(200);
|
||||
portduino_config.maxtophone = (yamlConfig["General"]["MaxMessageQueue"]).as<int>(100);
|
||||
|
||||
@@ -163,9 +163,6 @@ extern struct portduino_config_struct {
|
||||
int configDisplayMode = 0;
|
||||
bool has_configDisplayMode = false;
|
||||
|
||||
// Store and Forward++
|
||||
bool sfpp_stratum0 = false;
|
||||
|
||||
// General
|
||||
std::string mac_address = "";
|
||||
bool mac_address_explicit = false;
|
||||
|
||||
@@ -388,10 +388,10 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
|
||||
uint64_t sleepUsec = sleepMsec * 1000LL;
|
||||
|
||||
// NOTE! ESP docs say we must disable bluetooth and wifi before light sleep
|
||||
|
||||
#ifdef ESP_PD_DOMAIN_RTC_PERIPH
|
||||
// We want RTC peripherals to stay on
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
#endif
|
||||
#if defined(BUTTON_PIN) && defined(BUTTON_NEED_PULLUP)
|
||||
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
|
||||
#endif
|
||||
@@ -523,6 +523,8 @@ void enableModemSleep()
|
||||
esp32_config.max_freq_mhz = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ;
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6
|
||||
esp32_config.max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ;
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
esp32_config.max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ;
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
esp32_config.max_freq_mhz = CONFIG_ESP32C3_DEFAULT_CPU_FREQ_MHZ;
|
||||
#else
|
||||
|
||||
@@ -5,7 +5,7 @@ custom_esp32_kind = esp32
|
||||
custom_mtjson_part =
|
||||
platform =
|
||||
# renovate: datasource=custom.pio depName=platformio/espressif32 packageName=platformio/platform/espressif32
|
||||
platformio/espressif32@6.12.0
|
||||
platformio/espressif32@6.11.0
|
||||
|
||||
extra_scripts =
|
||||
${env.extra_scripts}
|
||||
|
||||
47
variants/esp32h2/esp32h2.ini
Normal file
47
variants/esp32h2/esp32h2.ini
Normal file
@@ -0,0 +1,47 @@
|
||||
[esp32h2_base]
|
||||
extends = esp32_base
|
||||
platform =
|
||||
# Do not renovate until we have switched to pioarduino tagged builds
|
||||
https://github.com/Jason2866/platform-espressif32/archive/39475a7213fa3a52b0c2048d1a31c215fc85fcf8.zip
|
||||
build_flags =
|
||||
${arduino_base.build_flags}
|
||||
-Wall
|
||||
-Wextra
|
||||
-Isrc/platform/esp32
|
||||
-std=c++11
|
||||
-DESP_OPENSSL_SUPPRESS_LEGACY_WARNING
|
||||
-DSERIAL_BUFFER_SIZE=4096
|
||||
-DLIBPAX_ARDUINO
|
||||
-DLIBPAX_WIFI
|
||||
-DLIBPAX_BLE
|
||||
-DMESHTASTIC_EXCLUDE_WEBSERVER
|
||||
;-DDEBUG_HEAP
|
||||
; TEMP
|
||||
-DHAS_BLUETOOTH=0
|
||||
-DMESHTASTIC_EXCLUDE_PAXCOUNTER
|
||||
-DMESHTASTIC_EXCLUDE_BLUETOOTH
|
||||
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
${networking_base.lib_deps}
|
||||
${environmental_base.lib_deps}
|
||||
${environmental_extra.lib_deps}
|
||||
${radiolib_base.lib_deps}
|
||||
# renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib
|
||||
lewisxhe/XPowersLib@0.3.1
|
||||
# renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master
|
||||
https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip
|
||||
# renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
|
||||
rweather/Crypto@0.4.0
|
||||
|
||||
build_src_filter =
|
||||
${esp32_base.build_src_filter} -<mesh/http>
|
||||
|
||||
monitor_speed = 460800
|
||||
monitor_filters = esp32_h2_exception_decoder
|
||||
|
||||
lib_ignore =
|
||||
NonBlockingRTTTL
|
||||
NimBLE-Arduino
|
||||
libpax
|
||||
|
||||
11
variants/esp32h2/waveshare-esp32-h2/platformio.ini
Normal file
11
variants/esp32h2/waveshare-esp32-h2/platformio.ini
Normal file
@@ -0,0 +1,11 @@
|
||||
[env:waveshare-esp32h2]
|
||||
extends = esp32h2_base
|
||||
board = esp32-h2-devkitm-1
|
||||
board_build.f_flash = 16000000L
|
||||
board_level = pr
|
||||
build_flags =
|
||||
${esp32h2_base.build_flags}
|
||||
-I variants/esp32h2/waveshare-esp32-h2
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DHAS_WIFI=0
|
||||
8
variants/esp32h2/waveshare-esp32-h2/variant.h
Normal file
8
variants/esp32h2/waveshare-esp32-h2/variant.h
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
#define HAS_SCREEN 0
|
||||
#define HAS_WIFI 0
|
||||
|
||||
#define LORA_SCK 4
|
||||
#define LORA_MISO 3
|
||||
#define LORA_MOSI 2
|
||||
#define LORA_CS 1
|
||||
@@ -45,7 +45,6 @@ build_flags = ${native_base.build_flags} -Os -lX11 -linput -lxkbcommon -ffunctio
|
||||
!pkg-config --libs openssl --silence-errors || :
|
||||
!pkg-config --cflags --libs sdl2 --silence-errors || :
|
||||
!pkg-config --cflags --libs libbsd-overlay --silence-errors || :
|
||||
!pkg-config --cflags --libs sqlite3 --silence-errors || :
|
||||
build_src_filter =
|
||||
${native_base.build_src_filter}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user