Merge branch 'master' into tft-gui-work

This commit is contained in:
Manuel 2024-03-11 16:22:56 +01:00 committed by GitHub
commit e24e4d99a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 248 additions and 68 deletions

View File

@ -35,6 +35,7 @@ jobs:
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}

62
.github/workflows/build_esp32_c3.yml vendored Normal file
View File

@ -0,0 +1,62 @@
name: Build ESP32-C3
on:
workflow_call:
inputs:
board:
required: true
type: string
permissions: read-all
jobs:
build-esp32-c3:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build base
id: base
uses: ./.github/actions/setup-base
- name: Pull web ui
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
with:
repo: meshtastic/web
file: build.tar
target: build.tar
token: ${{ secrets.GITHUB_TOKEN }}
- name: Unpack web ui
run: |
tar -xf build.tar -C data/static
rm build.tar
- name: Remove debug flags for release
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}
- name: Pull OTA Firmware
uses: dsaltares/fetch-gh-release-asset@a40c8b4a0471f9ab81bdf73a010f74cc51476ad4
with:
repo: meshtastic/firmware-ota
file: firmware-c3.bin
target: release/bleota-c3.bin
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get release version string
shell: bash
run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Store binaries as an artifact
uses: actions/upload-artifact@v3
with:
name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip
path: |
release/*.bin
release/*.elf

View File

@ -34,6 +34,7 @@ jobs:
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s2.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32s3.ini
sed -i '/DDEBUG_HEAP/d' ./arch/esp32/esp32c3.ini
- name: Build ESP32
run: bin/build-esp32.sh ${{ inputs.board }}

View File

@ -67,7 +67,6 @@ jobs:
- board: tlora-v2-1-1_6-tcxo
- board: tlora-v2-1-1_8
- board: tbeam
- board: heltec-ht62-esp32c3-sx1262
- board: heltec-v2_0
- board: heltec-v2_1
- board: tbeam0_7
@ -105,6 +104,16 @@ jobs:
with:
board: ${{ matrix.board }}
build-esp32-c3:
strategy:
fail-fast: false
matrix:
include:
- board: heltec-ht62-esp32c3-sx1262
uses: ./.github/workflows/build_esp32_c3.yml
with:
board: ${{ matrix.board }}
build-nrf52:
strategy:
fail-fast: false
@ -226,6 +235,7 @@ jobs:
[
build-esp32,
build-esp32-s3,
build-esp32-c3,
build-nrf52,
build-raspbian,
build-native,
@ -251,7 +261,7 @@ jobs:
id: version
- name: Move files up
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase_v2.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat ./firmware-raspbian-*/release/meshtasticd_linux_aarch64 ./firmware-raspbian-*/bin/config-dist.yaml
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./*esp32c3*/bleota-c3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase_v2.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat ./firmware-raspbian-*/release/meshtasticd_linux_aarch64 ./firmware-raspbian-*/bin/config-dist.yaml
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v3

View File

@ -31,9 +31,13 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% (
%PYTHON% -m esptool --baud 115200 erase_flash
%PYTHON% -m esptool --baud 115200 write_flash 0x00 %FILENAME%
@REM Account for S3 board's different OTA partition
@REM Account for S3 and C3 board's different OTA partition
IF x%FILENAME:s3=%==x%FILENAME% IF x%FILENAME:v3=%==x%FILENAME% IF x%FILENAME:t-deck=%==x%FILENAME% IF x%FILENAME:wireless-paper=%==x%FILENAME% IF x%FILENAME:wireless-tracker=%==x%FILENAME% (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
IF x%FILENAME:esp32c3=%==x%FILENAME% (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota.bin
) else (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-c3.bin
)
) else (
%PYTHON% -m esptool --baud 115200 write_flash 0x260000 bleota-s3.bin
)

View File

@ -1,12 +1,12 @@
#!/bin/sh
PYTHON=${PYTHON:-$(which python3 python|head -n 1)}
PYTHON=${PYTHON:-$(which python3 python | head -n 1)}
set -e
# Usage info
show_help() {
cat << EOF
cat <<EOF
Usage: $(basename $0) [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME|FILENAME]
Flash image file to device, but first erasing and writing system information"
@ -18,44 +18,50 @@ Flash image file to device, but first erasing and writing system information"
EOF
}
while getopts ":hp:P:f:" opt; do
case "${opt}" in
h)
show_help
exit 0
;;
p) export ESPTOOL_PORT=${OPTARG}
;;
P) PYTHON=${OPTARG}
;;
f) FILENAME=${OPTARG}
;;
*)
echo "Invalid flag."
show_help >&2
exit 1
;;
esac
case "${opt}" in
h)
show_help
exit 0
;;
p)
export ESPTOOL_PORT=${OPTARG}
;;
P)
PYTHON=${OPTARG}
;;
f)
FILENAME=${OPTARG}
;;
*)
echo "Invalid flag."
show_help >&2
exit 1
;;
esac
done
shift "$((OPTIND-1))"
shift "$((OPTIND - 1))"
[ -z "$FILENAME" -a -n "$1" ] && {
FILENAME=$1
shift
FILENAME=$1
shift
}
if [ -f "${FILENAME}" ] && [ ! -z "${FILENAME##*"update"*}" ]; then
if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
"$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
"$PYTHON" -m esptool erase_flash
"$PYTHON" -m esptool write_flash 0x00 ${FILENAME}
# Account for S3 board's different OTA partition
if [ ! -z "${FILENAME##*"s3"*}" ] && [ ! -z "${FILENAME##*"-v3"*}" ] && [ ! -z "${FILENAME##*"t-deck"*}" ] && [ ! -z "${FILENAME##*"wireless-paper"*}" ] && [ ! -z "${FILENAME##*"wireless-tracker"*}" ]; then
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
if [ -n "${FILENAME##*"s3"*}" ] && [ -n "${FILENAME##*"-v3"*}" ] && [ -n "${FILENAME##*"t-deck"*}" ] && [ -n "${FILENAME##*"wireless-paper"*}" ] && [ -n "${FILENAME##*"wireless-tracker"*}" ]; then
if [ -n "${FILENAME##*"esp32c3"*}" ]; then
"$PYTHON" -m esptool write_flash 0x260000 bleota.bin
else
"$PYTHON" -m esptool write_flash 0x260000 bleota-c3.bin
fi
else
"$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin
"$PYTHON" -m esptool write_flash 0x260000 bleota-s3.bin
fi
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
"$PYTHON" -m esptool write_flash 0x300000 littlefs-*.bin
else
show_help

View File

@ -242,4 +242,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MESHTASTIC_EXCLUDE_NEIGHBORINFO 1
#define MESHTASTIC_EXCLUDE_TRACEROUTE 1
#define MESHTASTIC_EXCLUDE_WAYPOINT 1
#define MESHTASTIC_EXCLUDE_INPUTBROKER 1
#define MESHTASTIC_EXCLUDE_SERIAL 1
#endif

View File

@ -71,28 +71,24 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
}
}
// Trigger the refresh in GxEPD2
LOG_DEBUG("Updating E-Paper... ");
#if false
// Currently unused; rescued from commented-out line during a refactor
// Use a meaningful macro here if variant doesn't want fast refresh
// Full update mode (slow)
adafruitDisplay->display(false)
#else
// Fast update mode
adafruitDisplay->nextPage();
#endif
#ifndef EINK_NO_HIBERNATE // Only hibernate if controller IC will preserve image memory
// Put screen to sleep to save power (possibly not necessary because we already did poweroff inside of display)
adafruitDisplay->hibernate();
#endif
// End the update process
endUpdate();
LOG_DEBUG("done\n");
return true;
}
// End the update process - virtual method, overriden in derived class
void EInkDisplay::endUpdate()
{
// Power off display hardware, then deep-sleep (Except Wireless Paper V1.1, no deep-sleep)
adafruitDisplay->hibernate();
}
// Write the buffer to the display memory
void EInkDisplay::display(void)
{
@ -188,6 +184,7 @@ bool EInkDisplay::connect()
// Init GxEPD2
adafruitDisplay->init();
adafruitDisplay->setRotation(3);
adafruitDisplay->clearScreen(); // Clearing now, so the boot logo will draw nice and smoothe (fast refresh)
}
#elif defined(PCA10059)
{

View File

@ -45,6 +45,13 @@ class EInkDisplay : public OLEDDisplay
*/
virtual bool forceDisplay(uint32_t msecLimit = 1000);
/**
* Run any code needed to complete an update, after the physical refresh has completed.
* Split from forceDisplay(), to enable async refresh in derived EInkDynamicDisplay class.
*
*/
virtual void endUpdate();
/**
* shim to make the abstraction happy
*

View File

@ -94,19 +94,29 @@ void EInkDynamicDisplay::adjustRefreshCounters()
// Trigger the display update by calling base class
bool EInkDynamicDisplay::update()
{
// Detemine the refresh mode to use, and start the update
bool refreshApproved = determineMode();
if (refreshApproved)
EInkDisplay::forceDisplay(0); // Bypass base class' own rate-limiting system
return refreshApproved; // (Unutilized) Base class promises to return true if update ran
#if defined(HAS_EINK_ASYNCFULL)
if (refreshApproved)
endOrDetach(); // Either endUpdate() right now (fast refresh), or set the async flag (full refresh)
#endif
return refreshApproved; // (Unutilized) Base class promises to return true if update ran
}
// Assess situation, pick a refresh type
bool EInkDynamicDisplay::determineMode()
{
checkWasFlooded();
checkForPromotion();
#if defined(HAS_EINK_ASYNCFULL)
checkAsyncFullRefresh();
#endif
checkRateLimiting();
// If too soon for a new time, abort here
// If too soon for a new frame, or display busy, abort early
if (refresh == SKIPPED) {
storeAndReset();
return false; // No refresh
@ -116,7 +126,7 @@ bool EInkDynamicDisplay::determineMode()
resetRateLimiting(); // Once determineMode() ends, will have to wait again
hashImage(); // Generate here, so we can still copy it to previousImageHash, even if we skip the comparison check
LOG_DEBUG("EInkDynamicDisplay: "); // Begin log entry
LOG_DEBUG("determineMode(): "); // Begin log entry
// Once mode determined, any remaining checks will bypass
checkCosmetic();
@ -151,13 +161,25 @@ bool EInkDynamicDisplay::determineMode()
}
}
// Did RESPONSIVE frames previously exceed the rate-limit for fast refresh?
void EInkDynamicDisplay::checkWasFlooded()
// Was a frame skipped (rate, display busy) that should have been a FAST refresh?
void EInkDynamicDisplay::checkForPromotion()
{
if (previousReason == EXCEEDED_RATELIMIT_FAST) {
// If so, allow a BACKGROUND frame to draw as RESPONSIVE
// Because we DID want a RESPONSIVE frame last time, we just didn't get it
// If a frame was skipped (rate, display busy), then promote a BACKGROUND frame
// Because we DID want a RESPONSIVE/COSMETIC/DEMAND_FULL frame last time, we just didn't get it
switch (previousReason) {
case ASYNC_REFRESH_BLOCKED_DEMANDFAST:
setFrameFlag(DEMAND_FAST);
break;
case ASYNC_REFRESH_BLOCKED_COSMETIC:
setFrameFlag(COSMETIC);
break;
case ASYNC_REFRESH_BLOCKED_RESPONSIVE:
case EXCEEDED_RATELIMIT_FAST:
setFrameFlag(RESPONSIVE);
break;
default:
break;
}
}
@ -381,4 +403,54 @@ void EInkDynamicDisplay::resetGhostPixelTracking()
}
#endif // EINK_LIMIT_GHOSTING_PX
#ifdef HAS_EINK_ASYNCFULL
// Check the status of an "async full-refresh", and run the finish-up code if the hardware is ready
void EInkDynamicDisplay::checkAsyncFullRefresh()
{
// No refresh taking place, continue with determineMode()
if (!asyncRefreshRunning)
return;
// Full refresh still running
if (adafruitDisplay->epd2.isBusy()) {
// No refresh
refresh = SKIPPED;
// Set the reason, marking what type of frame we're skipping
if (frameFlags & DEMAND_FAST)
reason = ASYNC_REFRESH_BLOCKED_DEMANDFAST;
else if (frameFlags & COSMETIC)
reason = ASYNC_REFRESH_BLOCKED_COSMETIC;
else if (frameFlags & RESPONSIVE)
reason = ASYNC_REFRESH_BLOCKED_RESPONSIVE;
else
reason = ASYNC_REFRESH_BLOCKED_BACKGROUND;
return;
}
// If we asyncRefreshRunning flag is still set, but display's BUSY pin reports the refresh is done
adafruitDisplay->endAsyncFull(); // Run the end of nextPage() code
EInkDisplay::endUpdate(); // Run base-class code to finish off update (NOT our derived class override)
asyncRefreshRunning = false; // Unset the flag
LOG_DEBUG("Async full-refresh complete\n");
// Note: this code only works because of a modification to meshtastic/GxEPD2.
// It is only equipped to intercept calls to nextPage()
}
// Figure out who runs the post-update code
void EInkDynamicDisplay::endOrDetach()
{
if (previousRefresh == FULL) { // Note: previousRefresh is the refresh from this loop.
asyncRefreshRunning = true; // Set the flag - picked up at start of determineMode(), next loop.
LOG_DEBUG("Async full-refresh begins\n");
}
// Fast Refresh
else
EInkDisplay::endUpdate(); // Still block while updating, but EInkDisplay needs us to call endUpdate() ourselves.
}
#endif // HAS_EINK_ASYNCFULL
#endif // USE_EINK_DYNAMICDISPLAY

View File

@ -44,6 +44,11 @@ class EInkDynamicDisplay : public EInkDisplay
};
enum reasonTypes : uint8_t { // How was the decision reached
NO_OBJECTIONS,
ASYNC_REFRESH_BLOCKED_DEMANDFAST,
ASYNC_REFRESH_BLOCKED_COSMETIC,
ASYNC_REFRESH_BLOCKED_RESPONSIVE,
ASYNC_REFRESH_BLOCKED_BACKGROUND,
DISPLAY_NOT_READY_FOR_FULL,
EXCEEDED_RATELIMIT_FAST,
EXCEEDED_RATELIMIT_FULL,
FLAGGED_COSMETIC,
@ -64,7 +69,7 @@ class EInkDynamicDisplay : public EInkDisplay
bool update(); // Trigger the display update - determine mode, then call base class
// Checks as part of determineMode()
void checkWasFlooded(); // Was the previous frame skipped for exceeding EINK_LIMIT_RATE_RESPONSIVE_SEC?
void checkForPromotion(); // Was a frame skipped (rate, display busy) that should have been a FAST refresh?
void checkRateLimiting(); // Is this frame too soon?
void checkCosmetic(); // Was the COSMETIC flag set?
void checkDemandingFast(); // Was the DEMAND_FAST flag set?
@ -99,6 +104,14 @@ class EInkDynamicDisplay : public EInkDisplay
uint8_t *dirtyPixels; // Any pixels that have been black since last full-refresh (dynamically allocated mem)
uint32_t ghostPixelCount = 0; // Number of pixels with problematic ghosting. Retained here for LOG_DEBUG use
#endif
// Conditional - async full refresh - only with modified meshtastic/GxEPD2
#if defined(HAS_EINK_ASYNCFULL)
void checkAsyncFullRefresh(); // Check the status of "async full-refresh"; run the post-update code if the hardware is ready
void endOrDetach(); // Run the post-update code, or delegate it off to checkAsyncFullRefresh()
void endUpdate() override {} // Disable base-class behavior of running post-update immediately after forceDisplay()
bool asyncRefreshRunning = false; // Flag, checked by checkAsyncFullRefresh()
#endif
};
#endif

View File

@ -248,4 +248,4 @@ extern uint32_t error_address;
#define Module_Config_size \
(ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + \
ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \
ModuleConfig_TelemetryConfig_size + ModuleConfig_size)
ModuleConfig_TelemetryConfig_size + ModuleConfig_size)

View File

@ -39,11 +39,11 @@
#if HAS_TELEMETRY
#include "modules/Telemetry/DeviceTelemetry.h"
#endif
#if HAS_SENSOR && !EXCLUDE_ENVIRONMENTAL_SENSOR
#if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
#include "modules/Telemetry/AirQualityTelemetry.h"
#include "modules/Telemetry/EnvironmentTelemetry.h"
#endif
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !EXCLUDE_POWER_TELEMETRY
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY
#include "modules/Telemetry/PowerTelemetry.h"
#endif
#ifdef ARCH_ESP32
@ -138,13 +138,13 @@ void setupModules()
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
new DeviceTelemetryModule();
#endif
#if HAS_SENSOR && !EXCLUDE_ENVIRONMENTAL_SENSOR
#if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
new EnvironmentTelemetryModule();
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) {
new AirQualityTelemetryModule();
}
#endif
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !EXCLUDE_POWER_TELEMETRY
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_POWER_TELEMETRY
new PowerTelemetryModule();
#endif
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \

View File

@ -12,7 +12,7 @@ int32_t SHT31Sensor::runOnce()
if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
status = sht31.begin();
status = sht31.begin(nodeTelemetrySensorsMap[sensorType].first);
return initI2CSensor();
}

View File

@ -5,7 +5,7 @@
class SHT31Sensor : public TelemetrySensor
{
private:
Adafruit_SHT31 sht31 = Adafruit_SHT31();
Adafruit_SHT31 sht31 = Adafruit_SHT31(nodeTelemetrySensorsMap[sensorType].second);
protected:
virtual void setup() override;

View File

@ -16,7 +16,7 @@ build_flags =
-D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached.
lib_deps =
${esp32s3_base.lib_deps}
https://github.com/meshtastic/GxEPD2
https://github.com/meshtastic/GxEPD2/
adafruit/Adafruit BusIO@^1.13.2
lewisxhe/PCF8563_Library@^1.0.1
upload_speed = 115200

View File

@ -5,7 +5,6 @@
#define I2C_SCL SCL
#define USE_EINK
#define EINK_NO_HIBERNATE
/*
* eink display pins

View File

@ -11,10 +11,16 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo
-DEINK_DISPLAY_MODEL=GxEPD2_154_D67
-DEINK_WIDTH=200
-DEINK_HEIGHT=200
-DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk
-DEINK_LIMIT_FASTREFRESH=20 ; How many consecutive fast-refreshes are permitted
-DEINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates
-DEINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates
-DEINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated
-DEINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached.
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/t-echo>
lib_deps =
${nrf52840_base.lib_deps}
https://github.com/meshtastic/GxEPD2#afce87a97dda1ac31d8a28dc8fa7c6f55dc96a61
https://github.com/meshtastic/GxEPD2
adafruit/Adafruit BusIO@^1.13.2
lewisxhe/PCF8563_Library@^1.0.1
;upload_protocol = fs