mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-14 09:02:14 +00:00
Merge branch 'master' into channel_num
This commit is contained in:
commit
4df81008bc
7
.github/workflows/main_matrix.yml
vendored
7
.github/workflows/main_matrix.yml
vendored
@ -153,12 +153,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
repo: "meshtastic/Meshtastic-OTA"
|
repo: "meshtastic/Meshtastic-OTA"
|
||||||
file: "firmware.bin"
|
file: "firmware.bin"
|
||||||
|
target: "release/bleota.bin"
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Move OTA Firmware
|
|
||||||
run: |
|
|
||||||
mv firmware.bin release/bleota.bin
|
|
||||||
|
|
||||||
- name: Get release version string
|
- name: Get release version string
|
||||||
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
run: echo "::set-output name=version::$(./bin/buildinfo.py long)"
|
||||||
id: version
|
id: version
|
||||||
@ -371,7 +368,7 @@ jobs:
|
|||||||
id: version
|
id: version
|
||||||
|
|
||||||
- name: Move files up
|
- name: Move files up
|
||||||
run: mv -b -t ./ ./*tbeam-1*/littlefs*.bin ./*tbeam-1*/bleota.bin ./*tbeam-1*/system-info.bin ./*tbeam-1*/partitions.bin ./**/firmware*.bin ./**/*.uf2 ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
|
run: mv -b -t ./ ./*tbeam-1*/littlefs*.bin ./*tbeam-1*/bleota.bin ./**/firmware*.bin ./**/*.uf2 ./**/*.elf ./**/meshtasticd_linux_amd64 ./*native*/*device-*.sh ./*native*/*device-*.bat
|
||||||
|
|
||||||
- name: Repackage in single firmware zip
|
- name: Repackage in single firmware zip
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
|
@ -31,7 +31,7 @@ lib_deps =
|
|||||||
${arduino_base.lib_deps}
|
${arduino_base.lib_deps}
|
||||||
${networking_base.lib_deps}
|
${networking_base.lib_deps}
|
||||||
${environmental_base.lib_deps}
|
${environmental_base.lib_deps}
|
||||||
https://github.com/caveman99/esp32_https_server.git
|
https://github.com/meshtastic/esp32_https_server.git
|
||||||
h2zero/NimBLE-Arduino@1.4.0
|
h2zero/NimBLE-Arduino@1.4.0
|
||||||
arduino-libraries/NTPClient@^3.1.0
|
arduino-libraries/NTPClient@^3.1.0
|
||||||
https://github.com/lewisxhe/XPowersLib.git
|
https://github.com/lewisxhe/XPowersLib.git
|
||||||
|
@ -29,14 +29,11 @@ SRCELF=.pio/build/$1/firmware.elf
|
|||||||
cp $SRCELF $OUTDIR/$basename.elf
|
cp $SRCELF $OUTDIR/$basename.elf
|
||||||
|
|
||||||
echo "Copying ESP32 bin file"
|
echo "Copying ESP32 bin file"
|
||||||
SRCBIN=.pio/build/$1/firmware.bin
|
SRCBIN=.pio/build/$1/firmware.factory.bin
|
||||||
cp $SRCBIN $OUTDIR/$basename.bin
|
cp $SRCBIN $OUTDIR/$basename.bin
|
||||||
|
|
||||||
echo "Building Filesystem for ESP32 targets"
|
echo "Building Filesystem for ESP32 targets"
|
||||||
pio run --environment tbeam -t buildfs
|
pio run --environment tbeam -t buildfs
|
||||||
cp .pio/build/tbeam/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
|
cp .pio/build/tbeam/littlefs.bin $OUTDIR/littlefs-$VERSION.bin
|
||||||
cp images/system-info.bin $OUTDIR/system-info.bin
|
|
||||||
|
|
||||||
cp .pio/build/$1/partitions.bin $OUTDIR/partitions.bin
|
|
||||||
cp bin/device-install.* $OUTDIR
|
cp bin/device-install.* $OUTDIR
|
||||||
cp bin/device-update.* $OUTDIR
|
cp bin/device-update.* $OUTDIR
|
||||||
|
@ -29,13 +29,11 @@ IF "__%FILENAME%__" == "____" (
|
|||||||
IF EXIST %FILENAME% (
|
IF EXIST %FILENAME% (
|
||||||
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
|
echo Trying to flash update %FILENAME%, but first erasing and writing system information"
|
||||||
%PYTHON% -m esptool --baud 115200 erase_flash
|
%PYTHON% -m esptool --baud 115200 erase_flash
|
||||||
%PYTHON% -m esptool --baud 115200 write_flash 0x1000 system-info.bin
|
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
|
||||||
%PYTHON% -m esptool --baud 115200 write_flash 0x8000 partitions.bin
|
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
|
||||||
for %%f in (littlefs-*.bin) do (
|
for %%f in (littlefs-*.bin) do (
|
||||||
%PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f
|
%PYTHON% -m esptool --baud 115200 write_flash 0x300000 %%f
|
||||||
)
|
)
|
||||||
%PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME%
|
|
||||||
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
|
|
||||||
) else (
|
) else (
|
||||||
echo "Invalid file: %FILENAME%"
|
echo "Invalid file: %FILENAME%"
|
||||||
goto HELP
|
goto HELP
|
||||||
|
@ -47,11 +47,10 @@ shift "$((OPTIND-1))"
|
|||||||
if [ -f "${FILENAME}" ]; then
|
if [ -f "${FILENAME}" ]; then
|
||||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||||
"$PYTHON" -m esptool erase_flash
|
"$PYTHON" -m esptool erase_flash
|
||||||
"$PYTHON" -m esptool write_flash 0x1000 system-info.bin
|
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
|
||||||
"$PYTHON" -m esptool write_flash 0x8000 partitions.bin
|
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
|
||||||
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
|
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
|
||||||
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
|
|
||||||
"$PYTHON" -m esptool write_flash 0x10000 ${FILENAME}
|
|
||||||
else
|
else
|
||||||
echo "Invalid file: ${FILENAME}"
|
echo "Invalid file: ${FILENAME}"
|
||||||
show_help
|
show_help
|
||||||
|
@ -28,7 +28,7 @@ IF "__%FILENAME%__" == "____" (
|
|||||||
)
|
)
|
||||||
IF EXIST %FILENAME% (
|
IF EXIST %FILENAME% (
|
||||||
echo Trying to flash update %FILENAME%
|
echo Trying to flash update %FILENAME%
|
||||||
%PYTHON% -m esptool --baud 115200 write_flash 0x10000 %FILENAME%
|
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
|
||||||
) else (
|
) else (
|
||||||
echo "Invalid file: %FILENAME%"
|
echo "Invalid file: %FILENAME%"
|
||||||
goto HELP
|
goto HELP
|
||||||
|
@ -44,7 +44,7 @@ shift "$((OPTIND-1))"
|
|||||||
|
|
||||||
if [ -f "${FILENAME}" ]; then
|
if [ -f "${FILENAME}" ]; then
|
||||||
echo "Trying to flash update ${FILENAME}."
|
echo "Trying to flash update ${FILENAME}."
|
||||||
$PYTHON -m esptool --baud 115200 write_flash 0x10000 ${FILENAME}
|
$PYTHON -m esptool --baud 115200 write_flash 0x00 ${FILENAME}
|
||||||
else
|
else
|
||||||
echo "Invalid file: ${FILENAME}"
|
echo "Invalid file: ${FILENAME}"
|
||||||
show_help
|
show_help
|
||||||
|
@ -1,17 +1,70 @@
|
|||||||
|
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import configparser
|
import configparser
|
||||||
import traceback
|
import traceback
|
||||||
import sys
|
import sys
|
||||||
|
from os.path import join
|
||||||
from readprops import readProps
|
from readprops import readProps
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
platform = env.PioPlatform()
|
||||||
|
|
||||||
|
def esp32_create_combined_bin(source, target, env):
|
||||||
|
# this sub is borrowed from ESPEasy build toolchain. It's licensed under GPL V3
|
||||||
|
# https://github.com/letscontrolit/ESPEasy/blob/mega/tools/pio/post_esp32.py
|
||||||
|
print("Generating combined binary for serial flashing")
|
||||||
|
|
||||||
|
app_offset = 0x10000
|
||||||
|
|
||||||
|
new_file_name = env.subst("$BUILD_DIR/${PROGNAME}.factory.bin")
|
||||||
|
sections = env.subst(env.get("FLASH_EXTRA_IMAGES"))
|
||||||
|
firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin")
|
||||||
|
chip = env.get("BOARD_MCU")
|
||||||
|
flash_size = env.BoardConfig().get("upload.flash_size")
|
||||||
|
flash_freq = env.BoardConfig().get("build.f_flash", '40m')
|
||||||
|
flash_freq = flash_freq.replace('000000L', 'm')
|
||||||
|
flash_mode = env.BoardConfig().get("build.flash_mode", "dio")
|
||||||
|
memory_type = env.BoardConfig().get("build.arduino.memory_type", "qio_qspi")
|
||||||
|
if flash_mode == "qio" or flash_mode == "qout":
|
||||||
|
flash_mode = "dio"
|
||||||
|
if memory_type == "opi_opi" or memory_type == "opi_qspi":
|
||||||
|
flash_mode = "dout"
|
||||||
|
cmd = [
|
||||||
|
"--chip",
|
||||||
|
chip,
|
||||||
|
"merge_bin",
|
||||||
|
"-o",
|
||||||
|
new_file_name,
|
||||||
|
"--flash_mode",
|
||||||
|
flash_mode,
|
||||||
|
"--flash_freq",
|
||||||
|
flash_freq,
|
||||||
|
"--flash_size",
|
||||||
|
flash_size,
|
||||||
|
]
|
||||||
|
|
||||||
|
print(" Offset | File")
|
||||||
|
for section in sections:
|
||||||
|
sect_adr, sect_file = section.split(" ", 1)
|
||||||
|
print(f" - {sect_adr} | {sect_file}")
|
||||||
|
cmd += [sect_adr, sect_file]
|
||||||
|
|
||||||
|
print(f" - {hex(app_offset)} | {firmware_name}")
|
||||||
|
cmd += [hex(app_offset), firmware_name]
|
||||||
|
|
||||||
|
print('Using esptool.py arguments: %s' % ' '.join(cmd))
|
||||||
|
|
||||||
|
esptool.main(cmd)
|
||||||
|
|
||||||
|
if (platform.name == "espressif32"):
|
||||||
|
sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
|
||||||
|
import esptool
|
||||||
|
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin)
|
||||||
|
|
||||||
Import("projenv")
|
Import("projenv")
|
||||||
|
|
||||||
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
|
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
|
||||||
verObj = readProps(prefsLoc)
|
verObj = readProps(prefsLoc)
|
||||||
print("Using meshtastic platformio-custom.py, firmware version " + verObj['long'])
|
print("Using meshtastic platformio-custom.py, firmware version " + verObj['long'])
|
||||||
# print("path is" + ','.join(sys.path))
|
|
||||||
|
|
||||||
# General options that are passed to the C and C++ compilers
|
# General options that are passed to the C and C++ compilers
|
||||||
projenv.Append(CCFLAGS=[
|
projenv.Append(CCFLAGS=[
|
||||||
|
Binary file not shown.
@ -65,7 +65,7 @@ framework = arduino
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
; Portduino is using meshtastic fork for now
|
; Portduino is using meshtastic fork for now
|
||||||
https://github.com/jgromes/RadioLib.git@5.3.0
|
https://github.com/jgromes/RadioLib.git@5.4.0
|
||||||
|
|
||||||
build_flags = ${env.build_flags} -Os
|
build_flags = ${env.build_flags} -Os
|
||||||
# -DRADIOLIB_GODMODE
|
# -DRADIOLIB_GODMODE
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 0328a5269f8368f1eaa617d0e39f886d03d44c76
|
Subproject commit dabfdfb90c62bd862536157431083f99c8fde003
|
@ -36,7 +36,7 @@
|
|||||||
#include "nimble/NimbleBluetooth.h"
|
#include "nimble/NimbleBluetooth.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HAS_WIFI
|
#if HAS_WIFI || defined(ARCH_PORTDUINO)
|
||||||
#include "mesh/wifi/WiFiServerAPI.h"
|
#include "mesh/wifi/WiFiServerAPI.h"
|
||||||
#include "mqtt/MQTT.h"
|
#include "mqtt/MQTT.h"
|
||||||
#endif
|
#endif
|
||||||
@ -45,6 +45,9 @@
|
|||||||
#include "RF95Interface.h"
|
#include "RF95Interface.h"
|
||||||
#include "SX1262Interface.h"
|
#include "SX1262Interface.h"
|
||||||
#include "SX1268Interface.h"
|
#include "SX1268Interface.h"
|
||||||
|
#if !HAS_RADIO && defined(ARCH_PORTDUINO)
|
||||||
|
#include "platform/portduino/SimRadio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if HAS_BUTTON
|
#if HAS_BUTTON
|
||||||
#include "ButtonThread.h"
|
#include "ButtonThread.h"
|
||||||
@ -385,7 +388,7 @@ void setup()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !HAS_RADIO
|
#ifdef ARCH_PORTDUINO
|
||||||
if (!rIf) {
|
if (!rIf) {
|
||||||
rIf = new SimRadio;
|
rIf = new SimRadio;
|
||||||
if (!rIf->init()) {
|
if (!rIf->init()) {
|
||||||
@ -411,7 +414,7 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARCH_PORTDUINO
|
#ifdef ARCH_PORTDUINO
|
||||||
initApiServer();
|
initApiServer(TCPPort);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Start airtime logger thread.
|
// Start airtime logger thread.
|
||||||
|
@ -20,6 +20,8 @@ extern bool isUSBPowered;
|
|||||||
|
|
||||||
extern uint8_t nodeTelemetrySensorsMap[TelemetrySensorType_LPS22+1];
|
extern uint8_t nodeTelemetrySensorsMap[TelemetrySensorType_LPS22+1];
|
||||||
|
|
||||||
|
extern int TCPPort; // set by Portduino
|
||||||
|
|
||||||
// Global Screen singleton.
|
// Global Screen singleton.
|
||||||
extern graphics::Screen *screen;
|
extern graphics::Screen *screen;
|
||||||
// extern Observable<meshtastic::PowerStatus> newPowerStatus; //TODO: move this to main-esp32.cpp somehow or a helper class
|
// extern Observable<meshtastic::PowerStatus> newPowerStatus; //TODO: move this to main-esp32.cpp somehow or a helper class
|
||||||
|
@ -112,7 +112,7 @@ void MeshModule::callPlugins(const MeshPacket &mp, RxSource src)
|
|||||||
bool rxChannelOk = !pi.boundChannel || (mp.from == 0) ||
|
bool rxChannelOk = !pi.boundChannel || (mp.from == 0) ||
|
||||||
!ch ||
|
!ch ||
|
||||||
strlen(ch->settings.name) > 0 ||
|
strlen(ch->settings.name) > 0 ||
|
||||||
strcmp(ch->settings.name, pi.boundChannel);
|
(strcmp(ch->settings.name, pi.boundChannel) == 0);
|
||||||
|
|
||||||
if (!rxChannelOk) {
|
if (!rxChannelOk) {
|
||||||
// no one should have already replied!
|
// no one should have already replied!
|
||||||
|
@ -123,6 +123,29 @@ void MeshService::reloadOwner()
|
|||||||
*/
|
*/
|
||||||
void MeshService::handleToRadio(MeshPacket &p)
|
void MeshService::handleToRadio(MeshPacket &p)
|
||||||
{
|
{
|
||||||
|
#ifdef ARCH_PORTDUINO
|
||||||
|
// Simulates device is receiving a packet via the LoRa chip
|
||||||
|
if (p.decoded.portnum == PortNum_SIMULATOR_APP) {
|
||||||
|
// Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first
|
||||||
|
Compressed scratch;
|
||||||
|
Compressed *decoded = NULL;
|
||||||
|
if (p.which_payload_variant == MeshPacket_decoded_tag) {
|
||||||
|
memset(&scratch, 0, sizeof(scratch));
|
||||||
|
p.decoded.payload.size = pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &Compressed_msg, &scratch);
|
||||||
|
if (p.decoded.payload.size) {
|
||||||
|
decoded = &scratch;
|
||||||
|
// Extract the original payload and replace
|
||||||
|
memcpy(&p.decoded.payload, &decoded->data, sizeof(decoded->data));
|
||||||
|
// Switch the port from PortNum_SIMULATOR_APP back to the original PortNum
|
||||||
|
p.decoded.portnum = decoded->portnum;
|
||||||
|
} else
|
||||||
|
DEBUG_MSG("Error decoding protobuf for simulator message!\n");
|
||||||
|
}
|
||||||
|
// Let SimRadio receive as if it did via its LoRa chip
|
||||||
|
SimRadio::instance->startReceive(&p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (p.from != 0) { // We don't let phones assign nodenums to their sent messages
|
if (p.from != 0) { // We don't let phones assign nodenums to their sent messages
|
||||||
DEBUG_MSG("Warning: phone tried to pick a nodenum, we don't allow that.\n");
|
DEBUG_MSG("Warning: phone tried to pick a nodenum, we don't allow that.\n");
|
||||||
p.from = 0;
|
p.from = 0;
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
#include "MeshTypes.h"
|
#include "MeshTypes.h"
|
||||||
#include "Observer.h"
|
#include "Observer.h"
|
||||||
#include "PointerQueue.h"
|
#include "PointerQueue.h"
|
||||||
|
#ifdef ARCH_PORTDUINO
|
||||||
|
#include "../platform/portduino/SimRadio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
|
* Top level app for this service. keeps the mesh, the radio config and the queue of received packets.
|
||||||
|
@ -117,7 +117,7 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
|||||||
size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||||
{
|
{
|
||||||
if (!available()) {
|
if (!available()) {
|
||||||
DEBUG_MSG("getFromRadio=not available\n");
|
// DEBUG_MSG("getFromRadio=not available\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// In case we send a FromRadio packet
|
// In case we send a FromRadio packet
|
||||||
@ -319,7 +319,7 @@ bool PhoneAPI::available()
|
|||||||
if (!packetForPhone)
|
if (!packetForPhone)
|
||||||
packetForPhone = service.getForPhone();
|
packetForPhone = service.getForPhone();
|
||||||
bool hasPacket = !!packetForPhone;
|
bool hasPacket = !!packetForPhone;
|
||||||
DEBUG_MSG("available hasPacket=%d\n", hasPacket);
|
// DEBUG_MSG("available hasPacket=%d\n", hasPacket);
|
||||||
return hasPacket;
|
return hasPacket;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -461,12 +461,6 @@ void RadioInterface::limitPower()
|
|||||||
DEBUG_MSG("Set radio: final power level=%d\n", power);
|
DEBUG_MSG("Set radio: final power level=%d\n", power);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorCode SimRadio::send(MeshPacket *p)
|
|
||||||
{
|
|
||||||
DEBUG_MSG("SimRadio.send\n");
|
|
||||||
packetPool.release(p);
|
|
||||||
return ERRNO_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioInterface::deliverToReceiver(MeshPacket *p)
|
void RadioInterface::deliverToReceiver(MeshPacket *p)
|
||||||
{
|
{
|
||||||
|
@ -212,11 +212,6 @@ class RadioInterface
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SimRadio : public RadioInterface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ErrorCode send(MeshPacket *p) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Debug printing for packets
|
/// Debug printing for packets
|
||||||
void printPacket(const char *prefix, const MeshPacket *p);
|
void printPacket(const char *prefix, const MeshPacket *p);
|
||||||
|
@ -74,6 +74,11 @@ typedef enum _PortNum {
|
|||||||
Maintained by Github user a-f-G-U-C (a Meshtastic contributor)
|
Maintained by Github user a-f-G-U-C (a Meshtastic contributor)
|
||||||
Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS */
|
Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS */
|
||||||
PortNum_ZPS_APP = 68,
|
PortNum_ZPS_APP = 68,
|
||||||
|
/* Used to let multiple instances of Linux native applications communicate
|
||||||
|
as if they did using their LoRa chip.
|
||||||
|
Maintained by GitHub user GUVWAF.
|
||||||
|
Project files at https://github.com/GUVWAF/Meshtasticator */
|
||||||
|
PortNum_SIMULATOR_APP = 69,
|
||||||
/* Private applications should use portnums >= 256.
|
/* Private applications should use portnums >= 256.
|
||||||
To simplify initial development and testing you can use "PRIVATE_APP"
|
To simplify initial development and testing you can use "PRIVATE_APP"
|
||||||
in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/Meshtastic-device/blob/master/bin/regen-protos.sh)) */
|
in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/Meshtastic-device/blob/master/bin/regen-protos.sh)) */
|
||||||
|
@ -4,11 +4,12 @@
|
|||||||
|
|
||||||
static WiFiServerPort *apiPort;
|
static WiFiServerPort *apiPort;
|
||||||
|
|
||||||
void initApiServer()
|
void initApiServer(int port)
|
||||||
{
|
{
|
||||||
// Start API server on port 4403
|
// Start API server on port 4403
|
||||||
if (!apiPort) {
|
if (!apiPort) {
|
||||||
apiPort = new WiFiServerPort();
|
apiPort = new WiFiServerPort(port);
|
||||||
|
DEBUG_MSG("API server listening on TCP port %d\n", port);
|
||||||
apiPort->init();
|
apiPort->init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,13 +57,11 @@ void WiFiServerPort::debugOut(char c)
|
|||||||
apiPort->openAPI->debugOut(c);
|
apiPort->openAPI->debugOut(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MESHTASTIC_PORTNUM 4403
|
|
||||||
|
|
||||||
WiFiServerPort::WiFiServerPort() : WiFiServer(MESHTASTIC_PORTNUM), concurrency::OSThread("ApiServer") {}
|
WiFiServerPort::WiFiServerPort(int port) : WiFiServer(port), concurrency::OSThread("ApiServer") {}
|
||||||
|
|
||||||
void WiFiServerPort::init()
|
void WiFiServerPort::init()
|
||||||
{
|
{
|
||||||
DEBUG_MSG("API server listening on TCP port %d\n", MESHTASTIC_PORTNUM);
|
|
||||||
begin();
|
begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,4 +79,4 @@ int32_t WiFiServerPort::runOnce()
|
|||||||
}
|
}
|
||||||
|
|
||||||
return 100; // only check occasionally for incoming connections
|
return 100; // only check occasionally for incoming connections
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ class WiFiServerPort : public WiFiServer, private concurrency::OSThread
|
|||||||
WiFiServerAPI *openAPI = NULL;
|
WiFiServerAPI *openAPI = NULL;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WiFiServerPort();
|
explicit WiFiServerPort(int port);
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
@ -55,4 +55,4 @@ class WiFiServerPort : public WiFiServer, private concurrency::OSThread
|
|||||||
int32_t runOnce() override;
|
int32_t runOnce() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
void initApiServer();
|
void initApiServer(int port=4403);
|
||||||
|
@ -51,13 +51,42 @@ class PolledIrqPin : public GPIOPin
|
|||||||
|
|
||||||
static GPIOPin *loraIrq;
|
static GPIOPin *loraIrq;
|
||||||
|
|
||||||
|
int TCPPort = 4403;
|
||||||
|
|
||||||
|
static error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||||
|
switch (key) {
|
||||||
|
case 'p':
|
||||||
|
if (sscanf(arg, "%d", &TCPPort) < 1)
|
||||||
|
return ARGP_ERR_UNKNOWN;
|
||||||
|
else
|
||||||
|
printf("Using TCP port %d\n", TCPPort);
|
||||||
|
break;
|
||||||
|
case ARGP_KEY_ARG:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return ARGP_ERR_UNKNOWN;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void portduinoCustomInit() {
|
||||||
|
static struct argp_option options[] = {{"port", 'p', "PORT", 0, "The TCP port to use."}, {0}};
|
||||||
|
static void *childArguments;
|
||||||
|
static char doc[] = "Meshtastic native build.";
|
||||||
|
static char args_doc[] = "...";
|
||||||
|
static struct argp argp = {options, parse_opt, args_doc, doc, 0, 0, 0};
|
||||||
|
const struct argp_child child = {&argp, OPTION_ARG_OPTIONAL, 0, 0};
|
||||||
|
portduinoAddArguments(child, childArguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** apps run under portduino can optionally define a portduinoSetup() to
|
/** apps run under portduino can optionally define a portduinoSetup() to
|
||||||
* use portduino specific init code (such as gpioBind) to setup portduino on their host machine,
|
* use portduino specific init code (such as gpioBind) to setup portduino on their host machine,
|
||||||
* before running 'arduino' code.
|
* before running 'arduino' code.
|
||||||
*/
|
*/
|
||||||
void portduinoSetup()
|
void portduinoSetup()
|
||||||
{
|
{
|
||||||
printf("Setting up Meshtastic on Porduino...\n");
|
printf("Setting up Meshtastic on Portduino...\n");
|
||||||
|
|
||||||
#ifdef PORTDUINO_LINUX_HARDWARE
|
#ifdef PORTDUINO_LINUX_HARDWARE
|
||||||
SPI.begin(); // We need to create SPI
|
SPI.begin(); // We need to create SPI
|
||||||
@ -86,6 +115,9 @@ void portduinoSetup()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
|
// Set the random seed equal to TCPPort to have a different seed per instance
|
||||||
|
randomSeed(TCPPort);
|
||||||
|
|
||||||
auto fakeBusy = new SimGPIOPin(SX126X_BUSY, "fakeBusy");
|
auto fakeBusy = new SimGPIOPin(SX126X_BUSY, "fakeBusy");
|
||||||
fakeBusy->writePin(LOW);
|
fakeBusy->writePin(LOW);
|
||||||
fakeBusy->setSilent(true);
|
fakeBusy->setSilent(true);
|
||||||
|
250
src/platform/portduino/SimRadio.cpp
Normal file
250
src/platform/portduino/SimRadio.cpp
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
#include "SimRadio.h"
|
||||||
|
#include "MeshService.h"
|
||||||
|
#include "Router.h"
|
||||||
|
|
||||||
|
SimRadio::SimRadio()
|
||||||
|
{
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimRadio *SimRadio::instance;
|
||||||
|
|
||||||
|
ErrorCode SimRadio::send(MeshPacket *p)
|
||||||
|
{
|
||||||
|
printPacket("enqueuing for send", p);
|
||||||
|
|
||||||
|
ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||||
|
|
||||||
|
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
|
||||||
|
packetPool.release(p);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set (random) transmit delay to let others reconfigure their radio,
|
||||||
|
// to avoid collisions and implement timing-based flooding
|
||||||
|
DEBUG_MSG("Set random delay before transmitting.\n");
|
||||||
|
setTransmitDelay();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimRadio::setTransmitDelay()
|
||||||
|
{
|
||||||
|
MeshPacket *p = txQueue.getFront();
|
||||||
|
// We want all sending/receiving to be done by our daemon thread.
|
||||||
|
// We use a delay here because this packet might have been sent in response to a packet we just received.
|
||||||
|
// So we want to make sure the other side has had a chance to reconfigure its radio.
|
||||||
|
|
||||||
|
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
|
||||||
|
* This assumption is valid because of the offset generated by the radio to account for the noise
|
||||||
|
* floor.
|
||||||
|
*/
|
||||||
|
if (p->rx_snr == 0 && p->rx_rssi == 0) {
|
||||||
|
startTransmitTimer(true);
|
||||||
|
} else {
|
||||||
|
// If there is a SNR, start a timer scaled based on that SNR.
|
||||||
|
DEBUG_MSG("rx_snr found. hop_limit:%d rx_snr:%f\n", p->hop_limit, p->rx_snr);
|
||||||
|
startTransmitTimerSNR(p->rx_snr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimRadio::startTransmitTimer(bool withDelay)
|
||||||
|
{
|
||||||
|
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||||
|
if (!txQueue.empty()) {
|
||||||
|
uint32_t delayMsec = !withDelay ? 1 : getTxDelayMsec();
|
||||||
|
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||||
|
delay(delayMsec);
|
||||||
|
onNotify(TRANSMIT_DELAY_COMPLETED);
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("TX QUEUE EMPTY!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimRadio::startTransmitTimerSNR(float snr)
|
||||||
|
{
|
||||||
|
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||||
|
if (!txQueue.empty()) {
|
||||||
|
uint32_t delayMsec = getTxDelayMsecWeighted(snr);
|
||||||
|
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||||
|
delay(delayMsec);
|
||||||
|
onNotify(TRANSMIT_DELAY_COMPLETED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimRadio::handleTransmitInterrupt()
|
||||||
|
{
|
||||||
|
// This can be null if we forced the device to enter standby mode. In that case
|
||||||
|
// ignore the transmit interrupt
|
||||||
|
if (sendingPacket)
|
||||||
|
completeSending();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimRadio::completeSending()
|
||||||
|
{
|
||||||
|
// We are careful to clear sending packet before calling printPacket because
|
||||||
|
// that can take a long time
|
||||||
|
auto p = sendingPacket;
|
||||||
|
sendingPacket = NULL;
|
||||||
|
|
||||||
|
if (p) {
|
||||||
|
txGood++;
|
||||||
|
printPacket("Completed sending", p);
|
||||||
|
|
||||||
|
// We are done sending that packet, release it
|
||||||
|
packetPool.release(p);
|
||||||
|
// DEBUG_MSG("Done with send\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Could we send right now (i.e. either not actively receving or transmitting)? */
|
||||||
|
bool SimRadio::canSendImmediately()
|
||||||
|
{
|
||||||
|
// We wait _if_ we are partially though receiving a packet (rather than just merely waiting for one).
|
||||||
|
// To do otherwise would be doubly bad because not only would we drop the packet that was on the way in,
|
||||||
|
// we almost certainly guarantee no one outside will like the packet we are sending.
|
||||||
|
bool busyTx = sendingPacket != NULL;
|
||||||
|
bool busyRx = isReceiving && isActivelyReceiving();
|
||||||
|
|
||||||
|
if (busyTx || busyRx) {
|
||||||
|
if (busyTx)
|
||||||
|
DEBUG_MSG("Can not send yet, busyTx\n");
|
||||||
|
if (busyRx)
|
||||||
|
DEBUG_MSG("Can not send yet, busyRx\n");
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimRadio::isActivelyReceiving()
|
||||||
|
{
|
||||||
|
return false; // TODO check how this should be simulated
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimRadio::isChannelActive()
|
||||||
|
{
|
||||||
|
return false; // TODO ask simulator
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||||
|
bool SimRadio::cancelSending(NodeNum from, PacketId id)
|
||||||
|
{
|
||||||
|
auto p = txQueue.remove(from, id);
|
||||||
|
if (p)
|
||||||
|
packetPool.release(p); // free the packet we just removed
|
||||||
|
|
||||||
|
bool result = (p != NULL);
|
||||||
|
DEBUG_MSG("cancelSending id=0x%x, removed=%d\n", id, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SimRadio::onNotify(uint32_t notification)
|
||||||
|
{
|
||||||
|
switch (notification) {
|
||||||
|
case ISR_TX:
|
||||||
|
handleTransmitInterrupt();
|
||||||
|
DEBUG_MSG("tx complete - starting timer\n");
|
||||||
|
startTransmitTimer();
|
||||||
|
break;
|
||||||
|
case ISR_RX:
|
||||||
|
DEBUG_MSG("rx complete - starting timer\n");
|
||||||
|
break;
|
||||||
|
case TRANSMIT_DELAY_COMPLETED:
|
||||||
|
DEBUG_MSG("delay done\n");
|
||||||
|
|
||||||
|
// If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
|
||||||
|
// has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
|
||||||
|
if (!txQueue.empty()) {
|
||||||
|
if (!canSendImmediately()) {
|
||||||
|
// DEBUG_MSG("Currently Rx/Tx-ing: set random delay\n");
|
||||||
|
setTransmitDelay(); // currently Rx/Tx-ing: reset random delay
|
||||||
|
} else {
|
||||||
|
if (isChannelActive()) { // check if there is currently a LoRa packet on the channel
|
||||||
|
// DEBUG_MSG("Channel is active: set random delay\n");
|
||||||
|
setTransmitDelay(); // reset random delay
|
||||||
|
} else {
|
||||||
|
// Send any outgoing packets we have ready
|
||||||
|
MeshPacket *txp = txQueue.dequeue();
|
||||||
|
assert(txp);
|
||||||
|
startSend(txp);
|
||||||
|
// Packet has been sent, count it toward our TX airtime utilization.
|
||||||
|
uint32_t xmitMsec = getPacketTime(txp);
|
||||||
|
airTime->logAirtime(TX_LOG, xmitMsec);
|
||||||
|
completeSending();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// DEBUG_MSG("done with txqueue\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0); // We expected to receive a valid notification from the ISR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** start an immediate transmit */
|
||||||
|
void SimRadio::startSend(MeshPacket * txp)
|
||||||
|
{
|
||||||
|
printPacket("Starting low level send", txp);
|
||||||
|
size_t numbytes = beginSending(txp);
|
||||||
|
MeshPacket* p = packetPool.allocCopy(*txp);
|
||||||
|
perhapsDecode(p);
|
||||||
|
Compressed c = Compressed_init_default;
|
||||||
|
c.portnum = p->decoded.portnum;
|
||||||
|
// DEBUG_MSG("Sending back to simulator with portNum %d\n", p->decoded.portnum);
|
||||||
|
if (p->decoded.payload.size <= sizeof(c.data.bytes)) {
|
||||||
|
memcpy(&c.data.bytes, p->decoded.payload.bytes, p->decoded.payload.size);
|
||||||
|
c.data.size = p->decoded.payload.size;
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("Payload size is larger than compressed message allows! Sending empty payload.\n");
|
||||||
|
}
|
||||||
|
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), Compressed_fields, &c);
|
||||||
|
p->decoded.portnum = PortNum_SIMULATOR_APP;
|
||||||
|
service.sendToPhone(p); // Sending back to simulator
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SimRadio::startReceive(MeshPacket *p) {
|
||||||
|
isReceiving = true;
|
||||||
|
handleReceiveInterrupt(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SimRadio::handleReceiveInterrupt(MeshPacket *p)
|
||||||
|
{
|
||||||
|
DEBUG_MSG("HANDLE RECEIVE INTERRUPT\n");
|
||||||
|
uint32_t xmitMsec;
|
||||||
|
assert(isReceiving);
|
||||||
|
isReceiving = false;
|
||||||
|
|
||||||
|
// read the number of actually received bytes
|
||||||
|
size_t length = getPacketLength(p);
|
||||||
|
xmitMsec = getPacketTime(length);
|
||||||
|
// DEBUG_MSG("Payload size %d vs length (includes header) %d\n", p->decoded.payload.size, length);
|
||||||
|
|
||||||
|
MeshPacket *mp = packetPool.allocCopy(*p); // keep a copy in packtPool
|
||||||
|
mp->which_payload_variant = MeshPacket_decoded_tag; // Mark that the payload is already decoded
|
||||||
|
|
||||||
|
printPacket("Lora RX", mp);
|
||||||
|
|
||||||
|
airTime->logAirtime(RX_LOG, xmitMsec);
|
||||||
|
|
||||||
|
deliverToReceiver(mp);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SimRadio::getPacketLength(MeshPacket *mp) {
|
||||||
|
auto &p = mp->decoded;
|
||||||
|
return (size_t)p.payload.size+sizeof(PacketHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t SimRadio::readData(uint8_t* data, size_t len) {
|
||||||
|
int16_t state = RADIOLIB_ERR_NONE;
|
||||||
|
|
||||||
|
if(state == RADIOLIB_ERR_NONE) {
|
||||||
|
// add null terminator
|
||||||
|
data[len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
87
src/platform/portduino/SimRadio.h
Normal file
87
src/platform/portduino/SimRadio.h
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RadioInterface.h"
|
||||||
|
#include "MeshPacketQueue.h"
|
||||||
|
#include "wifi/WiFiServerAPI.h"
|
||||||
|
|
||||||
|
#define RADIOLIB_EXCLUDE_HTTP
|
||||||
|
#include <RadioLib.h>
|
||||||
|
|
||||||
|
class SimRadio : public RadioInterface
|
||||||
|
{
|
||||||
|
enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debugging counts
|
||||||
|
*/
|
||||||
|
uint32_t rxBad = 0, rxGood = 0, txGood = 0;
|
||||||
|
|
||||||
|
MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE);
|
||||||
|
|
||||||
|
public:
|
||||||
|
SimRadio();
|
||||||
|
|
||||||
|
/** MeshService needs this to find our active instance
|
||||||
|
*/
|
||||||
|
static SimRadio *instance;
|
||||||
|
|
||||||
|
|
||||||
|
virtual ErrorCode send(MeshPacket *p) override;
|
||||||
|
|
||||||
|
/** can we detect a LoRa preamble on the current channel? */
|
||||||
|
virtual bool isChannelActive();
|
||||||
|
|
||||||
|
/** are we actively receiving a packet (only called during receiving state)
|
||||||
|
* This method is only public to facilitate debugging. Do not call.
|
||||||
|
*/
|
||||||
|
virtual bool isActivelyReceiving();
|
||||||
|
|
||||||
|
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||||
|
virtual bool cancelSending(NodeNum from, PacketId id) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start waiting to receive a message
|
||||||
|
*
|
||||||
|
* External functions can call this method to wake the device from sleep.
|
||||||
|
*/
|
||||||
|
virtual void startReceive(MeshPacket *p);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// are _trying_ to receive a packet currently (note - we might just be waiting for one)
|
||||||
|
bool isReceiving = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void setTransmitDelay();
|
||||||
|
|
||||||
|
/** random timer with certain min. and max. settings */
|
||||||
|
void startTransmitTimer(bool withDelay = true);
|
||||||
|
|
||||||
|
/** timer scaled to SNR of to be flooded packet */
|
||||||
|
void startTransmitTimerSNR(float snr);
|
||||||
|
|
||||||
|
void handleTransmitInterrupt();
|
||||||
|
void handleReceiveInterrupt(MeshPacket *p);
|
||||||
|
|
||||||
|
void onNotify(uint32_t notification);
|
||||||
|
|
||||||
|
// start an immediate transmit
|
||||||
|
virtual void startSend(MeshPacket *txp);
|
||||||
|
|
||||||
|
// derive packet length
|
||||||
|
size_t getPacketLength(MeshPacket *p);
|
||||||
|
|
||||||
|
int16_t readData(uint8_t* str, size_t len);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Could we send right now (i.e. either not actively receiving or transmitting)? */
|
||||||
|
virtual bool canSendImmediately();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a send was in progress finish it and return the buffer to the pool */
|
||||||
|
void completeSending();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SimRadio *simRadio;
|
Loading…
Reference in New Issue
Block a user