mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-27 18:31:37 +00:00
Merge branch 'T-beam-display-no-touch' of https://github.com/Nasimovy/meshtastic-firmware into T-beam-display-no-touch
This commit is contained in:
commit
60ee8ead63
32
.github/workflows/release_channels.yml
vendored
32
.github/workflows/release_channels.yml
vendored
@ -46,11 +46,14 @@ jobs:
|
|||||||
|
|
||||||
# Create a PR to bump version when a release is Published
|
# Create a PR to bump version when a release is Published
|
||||||
bump-version:
|
bump-version:
|
||||||
if: ${{ github.event.release.published }}
|
if: github.event.action == 'published'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
contents: write
|
contents: write
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@ -63,29 +66,42 @@ jobs:
|
|||||||
- name: Get release version string
|
- name: Get release version string
|
||||||
run: |
|
run: |
|
||||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
echo "short=$(./bin/buildinfo.py short)" >> $GITHUB_OUTPUT
|
||||||
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
|
echo "deb=$(./bin/buildinfo.py deb)" >> $GITHUB_OUTPUT
|
||||||
id: version
|
id: version
|
||||||
env:
|
env:
|
||||||
BUILD_LOCATION: local
|
BUILD_LOCATION: local
|
||||||
|
|
||||||
- name: Bump version.properties
|
- name: Bump version.properties
|
||||||
run: >-
|
run: |
|
||||||
bin/bump_version.py
|
# Bump version.properties
|
||||||
|
chmod +x ./bin/bump_version.py
|
||||||
|
./bin/bump_version.py
|
||||||
|
|
||||||
- name: Ensure debian deps are installed
|
- name: Ensure debian deps are installed
|
||||||
shell: bash
|
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update -y --fix-missing
|
sudo apt-get update -y --fix-missing
|
||||||
sudo apt-get install -y devscripts
|
sudo apt-get install -y devscripts
|
||||||
|
|
||||||
- name: Update debian changelog
|
- name: Update debian changelog
|
||||||
run: >-
|
run: |
|
||||||
debian/ci_changelog.sh
|
# Update debian changelog
|
||||||
|
chmod +x ./debian/ci_changelog.sh
|
||||||
|
./debian/ci_changelog.sh
|
||||||
|
|
||||||
- name: Create version.properties pull request
|
- name: Bump org.meshtastic.meshtasticd.metainfo.xml
|
||||||
|
run: |
|
||||||
|
# Bump org.meshtastic.meshtasticd.metainfo.xml
|
||||||
|
pip install -r bin/bump_metainfo/requirements.txt -q
|
||||||
|
chmod +x ./bin/bump_metainfo/bump_metainfo.py
|
||||||
|
./bin/bump_metainfo/bump_metainfo.py --file bin/org.meshtastic.meshtasticd.metainfo.xml "${{ steps.version.outputs.short }}"
|
||||||
|
|
||||||
|
- name: Create Bumps pull request
|
||||||
uses: peter-evans/create-pull-request@v7
|
uses: peter-evans/create-pull-request@v7
|
||||||
with:
|
with:
|
||||||
title: Bump version.properties
|
title: Bump release version
|
||||||
|
commit-message: automated bumps
|
||||||
add-paths: |
|
add-paths: |
|
||||||
version.properties
|
version.properties
|
||||||
debian/changelog
|
debian/changelog
|
||||||
|
bin/org.meshtastic.meshtasticd.metainfo.xml
|
||||||
|
@ -4,7 +4,7 @@ cli:
|
|||||||
plugins:
|
plugins:
|
||||||
sources:
|
sources:
|
||||||
- id: trunk
|
- id: trunk
|
||||||
ref: v1.6.7
|
ref: v1.6.8
|
||||||
uri: https://github.com/trunk-io/plugins
|
uri: https://github.com/trunk-io/plugins
|
||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
@ -16,7 +16,7 @@ lint:
|
|||||||
- terrascan@1.19.9
|
- terrascan@1.19.9
|
||||||
- trivy@0.61.0
|
- trivy@0.61.0
|
||||||
- taplo@0.9.3
|
- taplo@0.9.3
|
||||||
- ruff@0.11.4
|
- ruff@0.11.5
|
||||||
- isort@6.0.1
|
- isort@6.0.1
|
||||||
- markdownlint@0.44.0
|
- markdownlint@0.44.0
|
||||||
- oxipng@9.1.4
|
- oxipng@9.1.4
|
||||||
|
72
bin/bump_metainfo/bump_metainfo.py
Executable file
72
bin/bump_metainfo/bump_metainfo.py
Executable file
@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from defusedxml.ElementTree import parse
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
|
||||||
|
# Indent by 2 spaces to align with xml formatting.
|
||||||
|
def indent(elem, level=0):
|
||||||
|
i = "\n" + level * " "
|
||||||
|
if len(elem):
|
||||||
|
if not elem.text or not elem.text.strip():
|
||||||
|
elem.text = i + " "
|
||||||
|
for child in elem:
|
||||||
|
indent(child, level + 1)
|
||||||
|
if not child.tail or not child.tail.strip():
|
||||||
|
child.tail = i
|
||||||
|
if level and (not elem.tail or not elem.tail.strip()):
|
||||||
|
elem.tail = i
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Prepend new release entry to metainfo.xml file.")
|
||||||
|
parser.add_argument("--file", help="Path to the metainfo.xml file",
|
||||||
|
default="org.meshtastic.meshtasticd.metainfo.xml")
|
||||||
|
parser.add_argument("version", help="Version string (e.g. 2.6.4)")
|
||||||
|
parser.add_argument("--date", help="Release date (YYYY-MM-DD), defaults to today",
|
||||||
|
default=datetime.now(timezone.utc).date().isoformat())
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
tree = parse(args.file)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
releases = root.find('releases')
|
||||||
|
if releases is None:
|
||||||
|
raise RuntimeError("<releases> element not found in XML.")
|
||||||
|
|
||||||
|
existing_versions = {
|
||||||
|
release.get('version'): release
|
||||||
|
for release in releases.findall('release')
|
||||||
|
}
|
||||||
|
existing_release = existing_versions.get(args.version)
|
||||||
|
|
||||||
|
if existing_release is not None:
|
||||||
|
if not existing_release.get('date'):
|
||||||
|
print(f"Version {args.version} found without date. Adding date...")
|
||||||
|
existing_release.set('date', args.date)
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"Version {args.version} is already present with date, skipping insertion.")
|
||||||
|
else:
|
||||||
|
new_release = ET.Element('release', {
|
||||||
|
'version': args.version,
|
||||||
|
'date': args.date
|
||||||
|
})
|
||||||
|
url = ET.SubElement(new_release, 'url', {'type': 'details'})
|
||||||
|
url.text = f"https://github.com/meshtastic/firmware/releases?q=tag%3Av{args.version}"
|
||||||
|
|
||||||
|
releases.insert(0, new_release)
|
||||||
|
|
||||||
|
indent(releases, level=1)
|
||||||
|
releases.tail = "\n"
|
||||||
|
|
||||||
|
print(f"Inserted new release: {args.version}")
|
||||||
|
|
||||||
|
tree.write(args.file, encoding='UTF-8', xml_declaration=True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
1
bin/bump_metainfo/requirements.txt
Normal file
1
bin/bump_metainfo/requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
defusedxml==0.7.1
|
11
bin/config.d/lora-piggystick-lr1121.yaml
Normal file
11
bin/config.d/lora-piggystick-lr1121.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Lora:
|
||||||
|
Module: lr1121
|
||||||
|
CS: 0
|
||||||
|
IRQ: 6
|
||||||
|
Reset: 2
|
||||||
|
Busy: 4
|
||||||
|
spidev: ch341
|
||||||
|
DIO3_TCXO_VOLTAGE: 1.8
|
||||||
|
# USB_Serialnum: 12345678
|
||||||
|
USB_PID: 0x5512
|
||||||
|
USB_VID: 0x1A86
|
@ -87,8 +87,14 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
<release version="v2.6.4.b89355f" date="2025-04-10">
|
<release version="2.6.6">
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases/tag/v2.6.4.b89355f</url>
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.6.6</url>
|
||||||
|
</release>
|
||||||
|
<release version="2.6.5" date="2025-04-09">
|
||||||
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.6.5</url>
|
||||||
|
</release>
|
||||||
|
<release version="2.6.4" date="2025-03-29">
|
||||||
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.6.4</url>
|
||||||
</release>
|
</release>
|
||||||
</releases>
|
</releases>
|
||||||
</component>
|
</component>
|
53
boards/heltec_mesh_pocket.json
Normal file
53
boards/heltec_mesh_pocket.json
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "nrf52840_s140_v6.ld"
|
||||||
|
},
|
||||||
|
"core": "nRF5",
|
||||||
|
"cpu": "cortex-m4",
|
||||||
|
"extra_flags": "-DNRF52840_XXAA",
|
||||||
|
"f_cpu": "64000000L",
|
||||||
|
"hwids": [
|
||||||
|
["0x239A", "0x4405"],
|
||||||
|
["0x239A", "0x0029"],
|
||||||
|
["0x239A", "0x002A"]
|
||||||
|
],
|
||||||
|
"usb_product": "HT-n5262",
|
||||||
|
"mcu": "nrf52840",
|
||||||
|
"variant": "heltec_mesh_pocket",
|
||||||
|
"variants_dir": "variants",
|
||||||
|
"bsp": {
|
||||||
|
"name": "adafruit"
|
||||||
|
},
|
||||||
|
"softdevice": {
|
||||||
|
"sd_flags": "-DS140",
|
||||||
|
"sd_name": "s140",
|
||||||
|
"sd_version": "6.1.1",
|
||||||
|
"sd_fwid": "0x00B6"
|
||||||
|
},
|
||||||
|
"bootloader": {
|
||||||
|
"settings_addr": "0xFF000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectivity": ["bluetooth"],
|
||||||
|
"debug": {
|
||||||
|
"jlink_device": "nRF52840_xxAA",
|
||||||
|
"onboard_tools": ["jlink"],
|
||||||
|
"svd_path": "nrf52840.svd",
|
||||||
|
"openocd_target": "nrf52840-mdk-rs"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino"],
|
||||||
|
"name": "Heltec nrf (Adafruit BSP)",
|
||||||
|
"upload": {
|
||||||
|
"maximum_ram_size": 248832,
|
||||||
|
"maximum_size": 815104,
|
||||||
|
"speed": 115200,
|
||||||
|
"protocol": "nrfutil",
|
||||||
|
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"wait_for_upload_port": true
|
||||||
|
},
|
||||||
|
"url": "https://heltec.org/project/meshpocket/",
|
||||||
|
"vendor": "Heltec"
|
||||||
|
}
|
4
debian/ci_pack_sdeb.sh
vendored
4
debian/ci_pack_sdeb.sh
vendored
@ -5,8 +5,8 @@ export PLATFORMIO_PACKAGES_DIR=pio/packages
|
|||||||
export PLATFORMIO_CORE_DIR=pio/core
|
export PLATFORMIO_CORE_DIR=pio/core
|
||||||
|
|
||||||
# Download libraries to `pio`
|
# Download libraries to `pio`
|
||||||
platformio pkg install -e native
|
platformio pkg install -e native-tft
|
||||||
platformio pkg install -e native -t platformio/tool-scons@4.40502.0
|
platformio pkg install -e native-tft -t platformio/tool-scons@4.40502.0
|
||||||
# Compress `pio` directory to prevent dh_clean from sanitizing it
|
# Compress `pio` directory to prevent dh_clean from sanitizing it
|
||||||
tar -cf pio.tar pio/
|
tar -cf pio.tar pio/
|
||||||
rm -rf pio
|
rm -rf pio
|
||||||
|
5
debian/control
vendored
5
debian/control
vendored
@ -21,7 +21,10 @@ Build-Depends: debhelper-compat (= 13),
|
|||||||
openssl,
|
openssl,
|
||||||
libssl-dev,
|
libssl-dev,
|
||||||
libulfius-dev,
|
libulfius-dev,
|
||||||
liborcania-dev
|
liborcania-dev,
|
||||||
|
libx11-dev,
|
||||||
|
libinput-dev,
|
||||||
|
libxkbcommon-x11-dev
|
||||||
Standards-Version: 4.6.2
|
Standards-Version: 4.6.2
|
||||||
Homepage: https://github.com/meshtastic/firmware
|
Homepage: https://github.com/meshtastic/firmware
|
||||||
Rules-Requires-Root: no
|
Rules-Requires-Root: no
|
||||||
|
2
debian/meshtasticd.install
vendored
2
debian/meshtasticd.install
vendored
@ -1,4 +1,4 @@
|
|||||||
.pio/build/native/meshtasticd usr/sbin
|
.pio/build/native-tft/meshtasticd usr/sbin
|
||||||
|
|
||||||
bin/config.yaml etc/meshtasticd
|
bin/config.yaml etc/meshtasticd
|
||||||
bin/config.d/* etc/meshtasticd/available.d
|
bin/config.d/* etc/meshtasticd/available.d
|
||||||
|
4
debian/rules
vendored
4
debian/rules
vendored
@ -26,7 +26,7 @@ override_dh_auto_build:
|
|||||||
mkdir -p web && tar -xf web.tar -C web
|
mkdir -p web && tar -xf web.tar -C web
|
||||||
gunzip web/ -r
|
gunzip web/ -r
|
||||||
# Build with platformio
|
# Build with platformio
|
||||||
$(PIO_ENV) platformio run -e native
|
$(PIO_ENV) platformio run -e native-tft
|
||||||
# Move the binary and default config to the correct name
|
# Move the binary and default config to the correct name
|
||||||
mv .pio/build/native/program .pio/build/native/meshtasticd
|
mv .pio/build/native-tft/program .pio/build/native-tft/meshtasticd
|
||||||
cp bin/config-dist.yaml bin/config.yaml
|
cp bin/config-dist.yaml bin/config.yaml
|
||||||
|
@ -93,8 +93,8 @@ build_src_filter = ${env.build_src_filter} -<platform/portduino/> -<graphics/nic
|
|||||||
; Common libs for communicating over TCP/IP networks such as MQTT
|
; Common libs for communicating over TCP/IP networks such as MQTT
|
||||||
[networking_base]
|
[networking_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=custom.pio depName=PubSubClient packageName=knolleary/library/PubSubClient
|
# renovate: datasource=custom.pio depName=TBPubSubClient packageName=thingsboard/library/TBPubSubClient
|
||||||
knolleary/PubSubClient@2.8
|
thingsboard/TBPubSubClient@2.12.1
|
||||||
# renovate: datasource=custom.pio depName=NTPClient packageName=arduino-libraries/library/NTPClient
|
# renovate: datasource=custom.pio depName=NTPClient packageName=arduino-libraries/library/NTPClient
|
||||||
arduino-libraries/NTPClient@3.2.1
|
arduino-libraries/NTPClient@3.2.1
|
||||||
# renovate: datasource=custom.pio depName=Syslog packageName=arcao/library/Syslog
|
# renovate: datasource=custom.pio depName=Syslog packageName=arcao/library/Syslog
|
||||||
@ -108,7 +108,7 @@ lib_deps =
|
|||||||
[device-ui_base]
|
[device-ui_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=git-refs depName=meshtastic-device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic-device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
||||||
https://github.com/meshtastic/device-ui/archive/3cdb8a63039aa2cf426104ab02656996730f79fa.zip
|
https://github.com/meshtastic/device-ui/archive/da8fb5eaac7874c31508fad5252999ec82c02498.zip
|
||||||
|
|
||||||
; Common libs for environmental measurements in telemetry module
|
; Common libs for environmental measurements in telemetry module
|
||||||
; (not included in native / portduino)
|
; (not included in native / portduino)
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 5a5ab103d2f6aa071fca29417475681a2cec5dcf
|
Subproject commit b982b36dfab2e96b8f8be90af891c68ebf8790c2
|
@ -13,6 +13,9 @@
|
|||||||
"git-submodules": {
|
"git-submodules": {
|
||||||
"enabled": true
|
"enabled": true
|
||||||
},
|
},
|
||||||
|
"pip_requirements": {
|
||||||
|
"fileMatch": ["bin/bump_metainfo/requirements.txt"]
|
||||||
|
},
|
||||||
"commitMessageTopic": "{{depName}}",
|
"commitMessageTopic": "{{depName}}",
|
||||||
"labels": ["dependencies"],
|
"labels": ["dependencies"],
|
||||||
"customDatasources": {
|
"customDatasources": {
|
||||||
|
@ -181,7 +181,6 @@ bool EInkDisplay::connect()
|
|||||||
// Start HSPI
|
// Start HSPI
|
||||||
hspi = new SPIClass(HSPI);
|
hspi = new SPIClass(HSPI);
|
||||||
hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS
|
hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS); // SCLK, MISO, MOSI, SS
|
||||||
|
|
||||||
// VExt already enabled in setup()
|
// VExt already enabled in setup()
|
||||||
// RTC GPIO hold disabled in setup()
|
// RTC GPIO hold disabled in setup()
|
||||||
|
|
||||||
@ -218,6 +217,21 @@ bool EInkDisplay::connect()
|
|||||||
adafruitDisplay->setRotation(1);
|
adafruitDisplay->setRotation(1);
|
||||||
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
||||||
}
|
}
|
||||||
|
#elif defined(HELTEC_MESH_POCKET)
|
||||||
|
{
|
||||||
|
spi1 = &SPI1;
|
||||||
|
spi1->begin();
|
||||||
|
// VExt already enabled in setup()
|
||||||
|
// RTC GPIO hold disabled in setup()
|
||||||
|
|
||||||
|
// Create GxEPD2 objects
|
||||||
|
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, *spi1);
|
||||||
|
adafruitDisplay = new GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||||
|
|
||||||
|
// Init GxEPD2
|
||||||
|
adafruitDisplay->init();
|
||||||
|
adafruitDisplay->setRotation(3);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -73,6 +73,10 @@ class EInkDisplay : public OLEDDisplay
|
|||||||
SPIClass *hspi = NULL;
|
SPIClass *hspi = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HELTEC_MESH_POCKET)
|
||||||
|
SPIClass *spi1 = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// FIXME quick hack to limit drawing to a very slow rate
|
// FIXME quick hack to limit drawing to a very slow rate
|
||||||
uint32_t lastDrawMsec = 0;
|
uint32_t lastDrawMsec = 0;
|
||||||
|
68
src/graphics/niche/Drivers/EInk/LCMEN2R13ECC1.cpp
Normal file
68
src/graphics/niche/Drivers/EInk/LCMEN2R13ECC1.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "./LCMEN2R13ECC1.h"
|
||||||
|
|
||||||
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||||
|
|
||||||
|
using namespace NicheGraphics::Drivers;
|
||||||
|
|
||||||
|
// Map the display controller IC's output to the connected panel
|
||||||
|
void LCMEN2R13ECC1::configScanning()
|
||||||
|
{
|
||||||
|
// "Driver output control"
|
||||||
|
sendCommand(0x01);
|
||||||
|
sendData(0xF9);
|
||||||
|
sendData(0x00);
|
||||||
|
sendData(0x00);
|
||||||
|
|
||||||
|
// To-do: delete this method?
|
||||||
|
// Values set here might be redundant: F9, 00, 00 seems to be default
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specify which information is used to control the sequence of voltages applied to move the pixels
|
||||||
|
// - For this display, configUpdateSequence() specifies that a suitable LUT will be loaded from
|
||||||
|
// the controller IC's OTP memory, when the update procedure begins.
|
||||||
|
void LCMEN2R13ECC1::configWaveform()
|
||||||
|
{
|
||||||
|
switch (updateType) {
|
||||||
|
case FAST:
|
||||||
|
sendCommand(0x3C); // Border waveform:
|
||||||
|
sendData(0x85);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FULL:
|
||||||
|
default:
|
||||||
|
// From OTP memory
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LCMEN2R13ECC1::configUpdateSequence()
|
||||||
|
{
|
||||||
|
switch (updateType) {
|
||||||
|
case FAST:
|
||||||
|
sendCommand(0x22); // Set "update sequence"
|
||||||
|
sendData(0xFF); // Will load LUT from OTP memory, Display mode 2 "differential refresh"
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FULL:
|
||||||
|
default:
|
||||||
|
sendCommand(0x22); // Set "update sequence"
|
||||||
|
sendData(0xF7); // Will load LUT from OTP memory
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once the refresh operation has been started,
|
||||||
|
// begin periodically polling the display to check for completion, using the normal Meshtastic threading code
|
||||||
|
// Only used when refresh is "async"
|
||||||
|
void LCMEN2R13ECC1::detachFromUpdate()
|
||||||
|
{
|
||||||
|
switch (updateType) {
|
||||||
|
case FAST:
|
||||||
|
return beginPolling(50, 800); // At least 500ms for fast refresh
|
||||||
|
case FULL:
|
||||||
|
default:
|
||||||
|
return beginPolling(100, 2500); // At least 2 seconds for full refresh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
41
src/graphics/niche/Drivers/EInk/LCMEN2R13ECC1.h
Normal file
41
src/graphics/niche/Drivers/EInk/LCMEN2R13ECC1.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
E-Ink display driver
|
||||||
|
- SSD1680
|
||||||
|
- Manufacturer: WISEVAST
|
||||||
|
- Size: 2.13 inch
|
||||||
|
- Resolution: 122px x 255px
|
||||||
|
- Flex connector marking: Soldering connector, no connector is needed
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#include "./SSD16XX.h"
|
||||||
|
|
||||||
|
namespace NicheGraphics::Drivers
|
||||||
|
{
|
||||||
|
class LCMEN2R13ECC1 : public SSD16XX
|
||||||
|
{
|
||||||
|
// Display properties
|
||||||
|
private:
|
||||||
|
static constexpr uint32_t width = 122;
|
||||||
|
static constexpr uint32_t height = 250;
|
||||||
|
static constexpr UpdateTypes supported = (UpdateTypes)(FULL | FAST);
|
||||||
|
|
||||||
|
public:
|
||||||
|
LCMEN2R13ECC1() : SSD16XX(width, height, supported, 1) {} // Note: left edge of this display is offset by 1 byte
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void configScanning() override;
|
||||||
|
virtual void configWaveform() override;
|
||||||
|
virtual void configUpdateSequence() override;
|
||||||
|
void detachFromUpdate() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace NicheGraphics::Drivers
|
||||||
|
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
@ -11,10 +11,19 @@ InkHUD::LogoApplet::LogoApplet() : concurrency::OSThread("LogoApplet")
|
|||||||
OSThread::setIntervalFromNow(8 * 1000UL);
|
OSThread::setIntervalFromNow(8 * 1000UL);
|
||||||
OSThread::enabled = true;
|
OSThread::enabled = true;
|
||||||
|
|
||||||
|
// During onboarding, show the default short name as well as the version string
|
||||||
|
// This behavior assists manufacturers during mass production, and should not be modified without good reason
|
||||||
|
if (!settings->tips.safeShutdownSeen) {
|
||||||
|
fontTitle = fontLarge;
|
||||||
|
textLeft = xstr(APP_VERSION_SHORT);
|
||||||
|
textRight = owner.short_name;
|
||||||
|
textTitle = "Meshtastic";
|
||||||
|
} else {
|
||||||
|
fontTitle = fontSmall;
|
||||||
textLeft = "";
|
textLeft = "";
|
||||||
textRight = "";
|
textRight = "";
|
||||||
textTitle = xstr(APP_VERSION_SHORT);
|
textTitle = xstr(APP_VERSION_SHORT);
|
||||||
fontTitle = fontSmall;
|
}
|
||||||
|
|
||||||
bringToForeground();
|
bringToForeground();
|
||||||
// This is then drawn with a FULL refresh by Renderer::begin
|
// This is then drawn with a FULL refresh by Renderer::begin
|
||||||
|
@ -181,7 +181,7 @@ void TwoButton::isrSecondary()
|
|||||||
void TwoButton::startThread()
|
void TwoButton::startThread()
|
||||||
{
|
{
|
||||||
if (!OSThread::enabled) {
|
if (!OSThread::enabled) {
|
||||||
OSThread::setInterval(50);
|
OSThread::setInterval(10);
|
||||||
OSThread::enabled = true;
|
OSThread::enabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1310,7 +1310,7 @@ extern meshtastic_DeviceMetadata getDeviceMetadata()
|
|||||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_AUDIO_CONFIG;
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_AUDIO_CONFIG;
|
||||||
#endif
|
#endif
|
||||||
// Option to explicitly include canned messages for edge cases, e.g. niche graphics
|
// Option to explicitly include canned messages for edge cases, e.g. niche graphics
|
||||||
#if (!HAS_SCREEN && NO_EXT_GPIO) && !MESHTASTIC_INCLUDE_CANNEDMSG
|
#if (!HAS_SCREEN || NO_EXT_GPIO) || MESHTASTIC_EXCLUDE_CANNEDMESSAGES
|
||||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_CANNEDMSG_CONFIG;
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_CANNEDMSG_CONFIG;
|
||||||
#endif
|
#endif
|
||||||
#if NO_EXT_GPIO
|
#if NO_EXT_GPIO
|
||||||
@ -1318,11 +1318,11 @@ extern meshtastic_DeviceMetadata getDeviceMetadata()
|
|||||||
#endif
|
#endif
|
||||||
// Only edge case here is if we apply this a device with built in Accelerometer and want to detect interrupts
|
// Only edge case here is if we apply this a device with built in Accelerometer and want to detect interrupts
|
||||||
// We'll have to macro guard against those targets potentially
|
// We'll have to macro guard against those targets potentially
|
||||||
#if NO_EXT_GPIO
|
#if NO_EXT_GPIO || MESHTASTIC_EXCLUDE_DETECTIONSENSOR
|
||||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_DETECTIONSENSOR_CONFIG;
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_DETECTIONSENSOR_CONFIG;
|
||||||
#endif
|
#endif
|
||||||
// If we don't have any GPIO and we don't have GPS, no purpose in having serial config
|
// If we don't have any GPIO and we don't have GPS OR we don't want too - no purpose in having serial config
|
||||||
#if NO_EXT_GPIO && NO_GPS
|
#if NO_EXT_GPIO && NO_GPS || MESHTASTIC_EXCLUDE_SERIAL
|
||||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_SERIAL_CONFIG;
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_SERIAL_CONFIG;
|
||||||
#endif
|
#endif
|
||||||
#ifndef ARCH_ESP32
|
#ifndef ARCH_ESP32
|
||||||
|
@ -210,6 +210,14 @@ bool RadioLibInterface::canSleep()
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Allow other firmware components to ask whether we are currently sending a packet
|
||||||
|
Initially implemented to protect T-Echo's capacitive touch button from spurious presses during tx
|
||||||
|
*/
|
||||||
|
bool RadioLibInterface::isSending()
|
||||||
|
{
|
||||||
|
return sendingPacket != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||||
bool RadioLibInterface::cancelSending(NodeNum from, PacketId id)
|
bool RadioLibInterface::cancelSending(NodeNum from, PacketId id)
|
||||||
{
|
{
|
||||||
|
@ -132,6 +132,11 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
|
|||||||
*/
|
*/
|
||||||
virtual bool isActivelyReceiving() = 0;
|
virtual bool isActivelyReceiving() = 0;
|
||||||
|
|
||||||
|
/** Are we are currently sending a packet?
|
||||||
|
* This method is public, intending to expose this information to other firmware components
|
||||||
|
*/
|
||||||
|
virtual bool isSending();
|
||||||
|
|
||||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
/** 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;
|
virtual bool cancelSending(NodeNum from, PacketId id) override;
|
||||||
|
|
||||||
|
@ -239,6 +239,10 @@ typedef enum _meshtastic_HardwareModel {
|
|||||||
meshtastic_HardwareModel_HELTEC_SENSOR_HUB = 92,
|
meshtastic_HardwareModel_HELTEC_SENSOR_HUB = 92,
|
||||||
/* Reserved Fried Chicken ID for future use */
|
/* Reserved Fried Chicken ID for future use */
|
||||||
meshtastic_HardwareModel_RESERVED_FRIED_CHICKEN = 93,
|
meshtastic_HardwareModel_RESERVED_FRIED_CHICKEN = 93,
|
||||||
|
/* Heltec Magnetic Power Bank with Meshtastic compatible */
|
||||||
|
meshtastic_HardwareModel_HELTEC_MESH_POCKET = 94,
|
||||||
|
/* Seeed Solar Node */
|
||||||
|
meshtastic_HardwareModel_SEEED_SOLAR_NODE = 95,
|
||||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
@ -281,7 +281,7 @@ struct PubSubConfig {
|
|||||||
#if HAS_NETWORKING
|
#if HAS_NETWORKING
|
||||||
bool connectPubSub(const PubSubConfig &config, PubSubClient &pubSub, Client &client)
|
bool connectPubSub(const PubSubConfig &config, PubSubClient &pubSub, Client &client)
|
||||||
{
|
{
|
||||||
pubSub.setBufferSize(1024);
|
pubSub.setBufferSize(1024, 1024);
|
||||||
pubSub.setClient(client);
|
pubSub.setClient(client);
|
||||||
pubSub.setServer(config.serverAddr.c_str(), config.serverPort);
|
pubSub.setServer(config.serverAddr.c_str(), config.serverPort);
|
||||||
|
|
||||||
|
@ -81,6 +81,8 @@
|
|||||||
#define HW_VENDOR meshtastic_HardwareModel_MESHLINK
|
#define HW_VENDOR meshtastic_HardwareModel_MESHLINK
|
||||||
#elif defined(SEEED_XIAO_NRF52840_KIT)
|
#elif defined(SEEED_XIAO_NRF52840_KIT)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_XIAO_NRF52_KIT
|
#define HW_VENDOR meshtastic_HardwareModel_XIAO_NRF52_KIT
|
||||||
|
#elif defined(HELTEC_MESH_POCKET)
|
||||||
|
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_POCKET
|
||||||
#else
|
#else
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_NRF52_UNKNOWN
|
#define HW_VENDOR meshtastic_HardwareModel_NRF52_UNKNOWN
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,6 +26,10 @@
|
|||||||
#define OCV_ARRAY 2700, 2560, 2540, 2520, 2500, 2460, 2420, 2400, 2380, 2320, 1500
|
#define OCV_ARRAY 2700, 2560, 2540, 2520, 2500, 2460, 2420, 2400, 2380, 2320, 1500
|
||||||
#elif defined(TRACKER_T1000_E)
|
#elif defined(TRACKER_T1000_E)
|
||||||
#define OCV_ARRAY 4190, 4078, 4017, 3969, 3887, 3818, 3798, 3791, 3766, 3712, 3100
|
#define OCV_ARRAY 4190, 4078, 4017, 3969, 3887, 3818, 3798, 3791, 3766, 3712, 3100
|
||||||
|
#elif defined(HELTEC_MESH_POCKET_BATTERY_5000)
|
||||||
|
#define OCV_ARRAY 4300, 4240, 4120, 4000, 3888, 3800, 3740, 3698, 3655, 3580, 3400
|
||||||
|
#elif defined(HELTEC_MESH_POCKET_BATTERY_10000)
|
||||||
|
#define OCV_ARRAY 4100, 4060, 3960, 3840, 3729, 3625, 3550, 3500, 3420, 3345, 3100
|
||||||
#else // LiIon
|
#else // LiIon
|
||||||
#define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100
|
#define OCV_ARRAY 4190, 4050, 3990, 3890, 3800, 3720, 3630, 3530, 3420, 3300, 3100
|
||||||
#endif
|
#endif
|
||||||
|
107
variants/heltec_mesh_pocket/nicheGraphics.h
Normal file
107
variants/heltec_mesh_pocket/nicheGraphics.h
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||||
|
|
||||||
|
// InkHUD-specific components
|
||||||
|
// ---------------------------
|
||||||
|
#include "graphics/niche/InkHUD/InkHUD.h"
|
||||||
|
|
||||||
|
// Applets
|
||||||
|
#include "graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.h"
|
||||||
|
#include "graphics/niche/InkHUD/Applets/User/DM/DMApplet.h"
|
||||||
|
#include "graphics/niche/InkHUD/Applets/User/Heard/HeardApplet.h"
|
||||||
|
#include "graphics/niche/InkHUD/Applets/User/Positions/PositionsApplet.h"
|
||||||
|
#include "graphics/niche/InkHUD/Applets/User/RecentsList/RecentsListApplet.h"
|
||||||
|
#include "graphics/niche/InkHUD/Applets/User/ThreadedMessage/ThreadedMessageApplet.h"
|
||||||
|
|
||||||
|
// #include "graphics/niche/InkHUD/Applets/Examples/BasicExample/BasicExampleApplet.h"
|
||||||
|
// #include "graphics/niche/InkHUD/Applets/Examples/NewMsgExample/NewMsgExampleApplet.h"
|
||||||
|
|
||||||
|
// Shared NicheGraphics components
|
||||||
|
// --------------------------------
|
||||||
|
#include "graphics/niche/Drivers/EInk/LCMEN2R13ECC1.h"
|
||||||
|
#include "graphics/niche/Inputs/TwoButton.h"
|
||||||
|
|
||||||
|
#include "graphics/niche/Fonts/FreeSans6pt7b.h"
|
||||||
|
#include "graphics/niche/Fonts/FreeSans6pt8bCyrillic.h"
|
||||||
|
#include <Fonts/FreeSans9pt7b.h>
|
||||||
|
|
||||||
|
void setupNicheGraphics()
|
||||||
|
{
|
||||||
|
using namespace NicheGraphics;
|
||||||
|
|
||||||
|
// SPI
|
||||||
|
// -----------------------------
|
||||||
|
SPIClass *spi1 = &SPI1;
|
||||||
|
spi1->begin();
|
||||||
|
// Display is connected to SPI1
|
||||||
|
|
||||||
|
// E-Ink Driver
|
||||||
|
// -----------------------------
|
||||||
|
// Use E-Ink driver
|
||||||
|
Drivers::EInk *driver = new Drivers::LCMEN2R13ECC1;
|
||||||
|
driver->begin(spi1, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES);
|
||||||
|
|
||||||
|
// InkHUD
|
||||||
|
// ----------------------------
|
||||||
|
|
||||||
|
InkHUD::InkHUD *inkhud = InkHUD::InkHUD::getInstance();
|
||||||
|
|
||||||
|
// Set the driver
|
||||||
|
inkhud->setDriver(driver);
|
||||||
|
|
||||||
|
// Set how many FAST updates per FULL update
|
||||||
|
// Set how unhealthy additional FAST updates beyond this number are
|
||||||
|
inkhud->setDisplayResilience(10, 1.5);
|
||||||
|
|
||||||
|
// Prepare fonts
|
||||||
|
InkHUD::Applet::fontLarge = InkHUD::AppletFont(FreeSans9pt7b);
|
||||||
|
InkHUD::Applet::fontSmall = InkHUD::AppletFont(FreeSans6pt7b);
|
||||||
|
/*
|
||||||
|
// Font localization demo: Cyrillic
|
||||||
|
InkHUD::Applet::fontSmall = InkHUD::AppletFont(FreeSans6pt8bCyrillic);
|
||||||
|
InkHUD::Applet::fontSmall.addSubstitutionsWin1251();
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Customize default settings
|
||||||
|
inkhud->persistence->settings.userTiles.maxCount = 2; // How many tiles can the display handle?
|
||||||
|
inkhud->persistence->settings.rotation = 3; // 270 degrees clockwise
|
||||||
|
inkhud->persistence->settings.userTiles.count = 1; // One tile only by default, keep things simple for new users
|
||||||
|
inkhud->persistence->settings.optionalMenuItems.nextTile = true;
|
||||||
|
|
||||||
|
// Pick applets
|
||||||
|
inkhud->addApplet("All Messages", new InkHUD::AllMessageApplet, true, true); // Activated, autoshown
|
||||||
|
inkhud->addApplet("DMs", new InkHUD::DMApplet); // Inactive
|
||||||
|
inkhud->addApplet("Channel 0", new InkHUD::ThreadedMessageApplet(0)); // Inactive
|
||||||
|
inkhud->addApplet("Channel 1", new InkHUD::ThreadedMessageApplet(1)); // Inactive
|
||||||
|
inkhud->addApplet("Positions", new InkHUD::PositionsApplet, true); // Activated
|
||||||
|
inkhud->addApplet("Recents List", new InkHUD::RecentsListApplet); // Inactive
|
||||||
|
inkhud->addApplet("Heard", new InkHUD::HeardApplet, true, false, 0); // Activated, not autoshown, default on tile 0
|
||||||
|
// inkhud->addApplet("Basic", new InkHUD::BasicExampleApplet);
|
||||||
|
// inkhud->addApplet("NewMsg", new InkHUD::NewMsgExampleApplet);
|
||||||
|
|
||||||
|
// Start running InkHUD
|
||||||
|
inkhud->begin();
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
// --------------------------
|
||||||
|
|
||||||
|
Inputs::TwoButton *buttons = Inputs::TwoButton::getInstance(); // Shared NicheGraphics component
|
||||||
|
constexpr uint8_t MAIN_BUTTON = 0;
|
||||||
|
// constexpr uint8_t AUX_BUTTON = 1;
|
||||||
|
|
||||||
|
// Setup the main user button
|
||||||
|
buttons->setWiring(MAIN_BUTTON, Inputs::TwoButton::getUserButtonPin());
|
||||||
|
buttons->setHandlerShortPress(MAIN_BUTTON, []() { InkHUD::InkHUD::getInstance()->shortpress(); });
|
||||||
|
buttons->setHandlerLongPress(MAIN_BUTTON, []() { InkHUD::InkHUD::getInstance()->longpress(); });
|
||||||
|
|
||||||
|
// Setup the aux button
|
||||||
|
// Bonus feature of VME213
|
||||||
|
// buttons->setWiring(AUX_BUTTON, BUTTON_PIN_SECONDARY);
|
||||||
|
// buttons->setHandlerShortPress(AUX_BUTTON, []() { InkHUD::InkHUD::getInstance()->nextTile(); });
|
||||||
|
buttons->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
92
variants/heltec_mesh_pocket/platformio.ini
Normal file
92
variants/heltec_mesh_pocket/platformio.ini
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
; First prototype nrf52840/sx1262 device
|
||||||
|
[env:heltec-mesh-pocket-5000]
|
||||||
|
extends = nrf52840_base
|
||||||
|
board = heltec_mesh_pocket
|
||||||
|
debug_tool = jlink
|
||||||
|
|
||||||
|
# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling.
|
||||||
|
build_flags = ${nrf52840_base.build_flags} -Ivariants/heltec_mesh_pocket
|
||||||
|
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
|
||||||
|
-DHELTEC_MESH_POCKET
|
||||||
|
-DHELTEC_MESH_POCKET_BATTERY_5000
|
||||||
|
-DUSE_EINK
|
||||||
|
-DEINK_DISPLAY_MODEL=GxEPD2_213_B74
|
||||||
|
-DEINK_WIDTH=250
|
||||||
|
-DEINK_HEIGHT=122
|
||||||
|
-DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk
|
||||||
|
-DEINK_LIMIT_FASTREFRESH=10 ; 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
|
||||||
|
; -D EINK_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.
|
||||||
|
-DEINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting"
|
||||||
|
-DEINK_HASQUIRK_WEAKFASTREFRESH ; Pixels set with fast-refresh are easy to clear, disrupted by sunlight
|
||||||
|
|
||||||
|
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/heltec_mesh_pocket>
|
||||||
|
lib_deps =
|
||||||
|
${nrf52840_base.lib_deps}
|
||||||
|
lewisxhe/PCF8563_Library@^1.0.1
|
||||||
|
https://github.com/meshtastic/GxEPD2#b202ebfec6a4821e098cf7a625ba0f6f2400292d
|
||||||
|
|
||||||
|
|
||||||
|
[env:heltec-mesh-pocket-inkhud-5000]
|
||||||
|
extends = nrf52840_base, inkhud
|
||||||
|
board = heltec_mesh_pocket
|
||||||
|
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/heltec_mesh_pocket> ${inkhud.build_src_filter}
|
||||||
|
build_flags =
|
||||||
|
${inkhud.build_flags}
|
||||||
|
${nrf52840_base.build_flags}
|
||||||
|
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
|
||||||
|
-I variants/heltec_mesh_pocket
|
||||||
|
-D HELTEC_MESH_POCKET
|
||||||
|
-D HELTEC_MESH_POCKET_BATTERY_5000
|
||||||
|
lib_deps =
|
||||||
|
${inkhud.lib_deps} ; InkHUD libs first, so we get GFXRoot instead of AdafruitGFX
|
||||||
|
${nrf52840_base.lib_deps}
|
||||||
|
|
||||||
|
|
||||||
|
; First prototype nrf52840/sx1262 device
|
||||||
|
[env:heltec-mesh-pocket-10000]
|
||||||
|
extends = nrf52840_base
|
||||||
|
board = heltec_mesh_pocket
|
||||||
|
debug_tool = jlink
|
||||||
|
|
||||||
|
# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling.
|
||||||
|
build_flags = ${nrf52840_base.build_flags} -Ivariants/heltec_mesh_pocket
|
||||||
|
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
|
||||||
|
-DHELTEC_MESH_POCKET
|
||||||
|
-DHELTEC_MESH_POCKET_BATTERY_10000
|
||||||
|
-DUSE_EINK
|
||||||
|
-DEINK_DISPLAY_MODEL=GxEPD2_213_B74
|
||||||
|
-DEINK_WIDTH=250
|
||||||
|
-DEINK_HEIGHT=122
|
||||||
|
-DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk
|
||||||
|
-DEINK_LIMIT_FASTREFRESH=10 ; 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
|
||||||
|
; -D EINK_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.
|
||||||
|
-DEINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting"
|
||||||
|
-DEINK_HASQUIRK_WEAKFASTREFRESH ; Pixels set with fast-refresh are easy to clear, disrupted by sunlight
|
||||||
|
|
||||||
|
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/heltec_mesh_pocket>
|
||||||
|
lib_deps =
|
||||||
|
${nrf52840_base.lib_deps}
|
||||||
|
lewisxhe/PCF8563_Library@^1.0.1
|
||||||
|
https://github.com/meshtastic/GxEPD2#b202ebfec6a4821e098cf7a625ba0f6f2400292d
|
||||||
|
|
||||||
|
|
||||||
|
[env:heltec-mesh-pocket-inkhud-10000]
|
||||||
|
extends = nrf52840_base, inkhud
|
||||||
|
board = heltec_mesh_pocket
|
||||||
|
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/heltec_mesh_pocket> ${inkhud.build_src_filter}
|
||||||
|
build_flags =
|
||||||
|
${inkhud.build_flags}
|
||||||
|
${nrf52840_base.build_flags}
|
||||||
|
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
|
||||||
|
-I variants/heltec_mesh_pocket
|
||||||
|
-D HELTEC_MESH_POCKET
|
||||||
|
-D HELTEC_MESH_POCKET_BATTERY_10000
|
||||||
|
lib_deps =
|
||||||
|
${inkhud.lib_deps} ; InkHUD libs first, so we get GFXRoot instead of AdafruitGFX
|
||||||
|
${nrf52840_base.lib_deps}
|
11
variants/heltec_mesh_pocket/variant.cpp
Normal file
11
variants/heltec_mesh_pocket/variant.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include "variant.h"
|
||||||
|
#include "nrf.h"
|
||||||
|
#include "wiring_constants.h"
|
||||||
|
#include "wiring_digital.h"
|
||||||
|
|
||||||
|
const uint32_t g_ADigitalPinMap[] = {
|
||||||
|
// P0 - pins 0 and 1 are hardwired for xtal and should never be enabled
|
||||||
|
0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||||
|
|
||||||
|
// P1
|
||||||
|
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
|
132
variants/heltec_mesh_pocket/variant.h
Normal file
132
variants/heltec_mesh_pocket/variant.h
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
#ifndef _VARIANT_HELTEC_NRF_
|
||||||
|
#define _VARIANT_HELTEC_NRF_
|
||||||
|
/** Master clock frequency */
|
||||||
|
#define VARIANT_MCK (64000000ul)
|
||||||
|
|
||||||
|
#define USE_LFXO // Board uses 32khz crystal for LF
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
* Headers
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "WVariant.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
// Number of pins defined in PinDescription array
|
||||||
|
#define PINS_COUNT (48)
|
||||||
|
#define NUM_DIGITAL_PINS (48)
|
||||||
|
#define NUM_ANALOG_INPUTS (1)
|
||||||
|
#define NUM_ANALOG_OUTPUTS (0)
|
||||||
|
|
||||||
|
// LEDs
|
||||||
|
#define PIN_LED1 (13) // 13 red (confirmed on 1.0 board)
|
||||||
|
#define LED_RED PIN_LED1
|
||||||
|
#define LED_BLUE PIN_LED1
|
||||||
|
#define LED_GREEN PIN_LED1
|
||||||
|
#define LED_BUILTIN LED_BLUE
|
||||||
|
#define LED_CONN LED_BLUE
|
||||||
|
#define LED_STATE_ON 0 // State when LED is lit
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Buttons
|
||||||
|
*/
|
||||||
|
#define PIN_BUTTON1 (32 + 10)
|
||||||
|
// #define PIN_BUTTON2 (0 + 18) // 0.18 is labeled on the board as RESET but we configure it in the bootloader as a regular
|
||||||
|
// GPIO
|
||||||
|
|
||||||
|
/*
|
||||||
|
No longer populated on PCB
|
||||||
|
*/
|
||||||
|
#define PIN_SERIAL2_RX (0 + 7)
|
||||||
|
#define PIN_SERIAL2_TX (0 + 8)
|
||||||
|
// #define PIN_SERIAL2_EN (0 + 17)
|
||||||
|
|
||||||
|
/**
|
||||||
|
Wire Interfaces
|
||||||
|
*/
|
||||||
|
#define WIRE_INTERFACES_COUNT 1
|
||||||
|
|
||||||
|
#define PIN_WIRE_SDA (32 + 15)
|
||||||
|
#define PIN_WIRE_SCL (32 + 13)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lora radio
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define USE_SX1262
|
||||||
|
#define SX126X_CS (0 + 26) // FIXME - we really should define LORA_CS instead
|
||||||
|
#define LORA_CS (0 + 26)
|
||||||
|
#define SX126X_DIO1 (0 + 16)
|
||||||
|
// Note DIO2 is attached internally to the module to an analog switch for TX/RX switching
|
||||||
|
// #define SX1262_DIO3 (0 + 21)
|
||||||
|
// This is used as an *output* from the sx1262 and connected internally to power the tcxo, do not drive from the
|
||||||
|
// main
|
||||||
|
// CPU?
|
||||||
|
#define SX126X_BUSY (0 + 15)
|
||||||
|
#define SX126X_RESET (0 + 12)
|
||||||
|
// Not really an E22 but TTGO seems to be trying to clone that
|
||||||
|
#define SX126X_DIO2_AS_RF_SWITCH
|
||||||
|
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||||
|
|
||||||
|
// Display (E-Ink)
|
||||||
|
#define PIN_EINK_CS 24
|
||||||
|
#define PIN_EINK_BUSY 32 + 6
|
||||||
|
#define PIN_EINK_DC 31
|
||||||
|
#define PIN_EINK_RES 32 + 4
|
||||||
|
#define PIN_EINK_SCLK 22
|
||||||
|
#define PIN_EINK_MOSI 20
|
||||||
|
|
||||||
|
#define PIN_SPI1_MISO -1
|
||||||
|
#define PIN_SPI1_MOSI PIN_EINK_MOSI
|
||||||
|
#define PIN_SPI1_SCK PIN_EINK_SCLK
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPS pins
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PIN_SERIAL1_RX 32 + 5
|
||||||
|
#define PIN_SERIAL1_TX 32 + 7
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPI Interfaces
|
||||||
|
*/
|
||||||
|
#define SPI_INTERFACES_COUNT 2
|
||||||
|
|
||||||
|
// For LORA, spi 0
|
||||||
|
#define PIN_SPI_MISO (32 + 9)
|
||||||
|
#define PIN_SPI_MOSI (0 + 5)
|
||||||
|
#define PIN_SPI_SCK (0 + 4)
|
||||||
|
|
||||||
|
// #define PIN_PWR_EN (0 + 6)
|
||||||
|
|
||||||
|
// To debug via the segger JLINK console rather than the CDC-ACM serial device
|
||||||
|
// #define USE_SEGGER
|
||||||
|
|
||||||
|
// Battery
|
||||||
|
// The battery sense is hooked to pin A0 (4)
|
||||||
|
// it is defined in the anlaolgue pin section of this file
|
||||||
|
// and has 12 bit resolution
|
||||||
|
|
||||||
|
#define ADC_CTRL 32 + 2
|
||||||
|
#define ADC_CTRL_ENABLED HIGH
|
||||||
|
#define BATTERY_PIN 29
|
||||||
|
#define ADC_RESOLUTION 14
|
||||||
|
|
||||||
|
#define BATTERY_SENSE_RESOLUTION_BITS 12
|
||||||
|
#define BATTERY_SENSE_RESOLUTION 4096.0
|
||||||
|
#undef AREF_VOLTAGE
|
||||||
|
#define AREF_VOLTAGE 3.0
|
||||||
|
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||||
|
#define ADC_MULTIPLIER (4.90F)
|
||||||
|
|
||||||
|
#undef HAS_GPS
|
||||||
|
#define HAS_GPS 0
|
||||||
|
#define HAS_RTC 0
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -29,6 +29,12 @@
|
|||||||
#include "graphics/niche/Fonts/FreeSans6pt8bCyrillic.h"
|
#include "graphics/niche/Fonts/FreeSans6pt8bCyrillic.h"
|
||||||
#include <Fonts/FreeSans9pt7b.h>
|
#include <Fonts/FreeSans9pt7b.h>
|
||||||
|
|
||||||
|
// Special case - fix T-Echo's touch button
|
||||||
|
// ----------------------------------------
|
||||||
|
// On a handful of T-Echos, LoRa TX triggers the capacitive touch
|
||||||
|
// To avoid this, we lockout the button during TX
|
||||||
|
#include "mesh/RadioLibInterface.h"
|
||||||
|
|
||||||
void setupNicheGraphics()
|
void setupNicheGraphics()
|
||||||
{
|
{
|
||||||
using namespace NicheGraphics;
|
using namespace NicheGraphics;
|
||||||
@ -115,13 +121,22 @@ void setupNicheGraphics()
|
|||||||
buttons->setWiring(TOUCH_BUTTON, PIN_BUTTON_TOUCH);
|
buttons->setWiring(TOUCH_BUTTON, PIN_BUTTON_TOUCH);
|
||||||
buttons->setTiming(TOUCH_BUTTON, 50, 5000); // 5 seconds before latch - limited by T-Echo's capacitive touch IC
|
buttons->setTiming(TOUCH_BUTTON, 50, 5000); // 5 seconds before latch - limited by T-Echo's capacitive touch IC
|
||||||
buttons->setHandlerDown(TOUCH_BUTTON, [backlight]() {
|
buttons->setHandlerDown(TOUCH_BUTTON, [backlight]() {
|
||||||
|
// Discard the button press if radio is active
|
||||||
|
// Rare hardware fault: LoRa activity triggers touch button
|
||||||
|
if (!RadioLibInterface::instance || RadioLibInterface::instance->isSending())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Backlight on (while held)
|
||||||
backlight->peek();
|
backlight->peek();
|
||||||
InkHUD::InkHUD::getInstance()->persistence->settings.optionalMenuItems.backlight =
|
|
||||||
false; // We've proved user still has the button. No need to make backlight togglable via the menu.
|
// Handler has run, which confirms touch button wasn't removed as part of DIY build.
|
||||||
|
// No longer need the fallback backlight toggle in menu.
|
||||||
|
InkHUD::InkHUD::getInstance()->persistence->settings.optionalMenuItems.backlight = false;
|
||||||
});
|
});
|
||||||
buttons->setHandlerLongPress(TOUCH_BUTTON, [backlight]() { backlight->latch(); });
|
buttons->setHandlerLongPress(TOUCH_BUTTON, [backlight]() { backlight->latch(); });
|
||||||
buttons->setHandlerShortPress(TOUCH_BUTTON, [backlight]() { backlight->off(); });
|
buttons->setHandlerShortPress(TOUCH_BUTTON, [backlight]() { backlight->off(); });
|
||||||
|
|
||||||
|
// Begin handling button events
|
||||||
buttons->start();
|
buttons->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
14
variants/tbeam_TFT/platformio.ini
Normal file
14
variants/tbeam_TFT/platformio.ini
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
; The 1.0 release of the TBEAM board
|
||||||
|
[env:tbeam_TFT]
|
||||||
|
extends = esp32_base
|
||||||
|
board = ttgo-t-beam
|
||||||
|
board_check = true
|
||||||
|
lib_deps = ${esp32_base.lib_deps}
|
||||||
|
https://github.com/Nasimovy/st7796/archive/refs/tags/1.0.5.zip ; display addon
|
||||||
|
build_flags = ${esp32_base.build_flags}
|
||||||
|
-DTBEAM_V10
|
||||||
|
-Ivariants/tbeam_TFT
|
||||||
|
-DGPS_POWER_TOGGLE ; comment this line to disable double press function on the user button to turn off gps entirely.
|
||||||
|
-DBOARD_HAS_PSRAM
|
||||||
|
-mfix-esp32-psram-cache-issue
|
||||||
|
upload_speed = 921600
|
60
variants/tbeam_TFT/variant.h
Normal file
60
variants/tbeam_TFT/variant.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// #define BUTTON_NEED_PULLUP // if set we need to turn on the internal CPU pullup during sleep
|
||||||
|
|
||||||
|
#define I2C_SDA 21
|
||||||
|
#define I2C_SCL 22
|
||||||
|
|
||||||
|
// Display addon
|
||||||
|
#define USE_ST7796
|
||||||
|
#define ST7796_NSS 25
|
||||||
|
#define ST7796_RS 13 // DC
|
||||||
|
#define ST7796_SDA 14 // MOSI
|
||||||
|
#define ST7796_SCK 15
|
||||||
|
#define ST7796_RESET 2
|
||||||
|
#define ST7796_MISO -1
|
||||||
|
#define ST7796_BUSY -1
|
||||||
|
#define VTFT_LEDA 4
|
||||||
|
#define TFT_SPI_FREQUENCY 500000
|
||||||
|
#define TFT_HEIGHT 222
|
||||||
|
#define TFT_WIDTH 480
|
||||||
|
#define BRIGHTNESS_DEFAULT 100 // Medium Low Brightnes
|
||||||
|
|
||||||
|
#define BUTTON_PIN 38 // The middle button GPIO on the T-Beam
|
||||||
|
// #define BUTTON_PIN_ALT 13 // Alternate GPIO for an external button if needed. Does anyone use this? It is not documented
|
||||||
|
// anywhere.
|
||||||
|
// #define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Module.
|
||||||
|
|
||||||
|
// #define LED_STATE_ON 0 // State when LED is lit
|
||||||
|
// #define LED_PIN 4 // Newer tbeams (1.1) have an extra led on GPIO4
|
||||||
|
|
||||||
|
// TTGO uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
|
||||||
|
// not found then probe for SX1262
|
||||||
|
#define USE_RF95 // RFM95/SX127x
|
||||||
|
#define USE_SX1262
|
||||||
|
#define USE_SX1268
|
||||||
|
|
||||||
|
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||||
|
#define LORA_RESET 23
|
||||||
|
#define LORA_DIO1 33 // SX1262 IRQ
|
||||||
|
#define LORA_DIO2 32 // SX1262 BUSY
|
||||||
|
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||||
|
|
||||||
|
#ifdef USE_SX1262
|
||||||
|
#define SX126X_CS LORA_CS // FIXME - we really should define LORA_CS instead
|
||||||
|
#define SX126X_DIO1 LORA_DIO1
|
||||||
|
#define SX126X_BUSY LORA_DIO2
|
||||||
|
#define SX126X_RESET LORA_RESET
|
||||||
|
// Not really an E22 but TTGO seems to be trying to clone that
|
||||||
|
#define SX126X_DIO2_AS_RF_SWITCH
|
||||||
|
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||||
|
// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
|
||||||
|
// code)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Leave undefined to disable our PMU IRQ handler. DO NOT ENABLE THIS because the pmuirq can cause sperious interrupts
|
||||||
|
// and waking from light sleep
|
||||||
|
// #define PMU_IRQ 35
|
||||||
|
#define HAS_AXP192
|
||||||
|
#define GPS_UBLOX
|
||||||
|
#define GPS_RX_PIN 34
|
||||||
|
#define GPS_TX_PIN 12
|
||||||
|
// #define GPS_DEBUG
|
@ -4,3 +4,4 @@ extends = esp32_base
|
|||||||
board = ttgo-lora32-v1
|
board = ttgo-lora32-v1
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_base.build_flags} -D TLORA_V1_3 -I variants/tlora_v1_3
|
${esp32_base.build_flags} -D TLORA_V1_3 -I variants/tlora_v1_3
|
||||||
|
upload_speed = 115200
|
@ -5,3 +5,4 @@ board_check = true
|
|||||||
build_flags =
|
build_flags =
|
||||||
${esp32_base.build_flags} -D TLORA_V2_1_16 -I variants/tlora_v2_1_16
|
${esp32_base.build_flags} -D TLORA_V2_1_16 -I variants/tlora_v2_1_16
|
||||||
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
||||||
|
upload_speed = 115200
|
@ -8,3 +8,4 @@ build_flags =
|
|||||||
-I variants/tlora_v2_1_16
|
-I variants/tlora_v2_1_16
|
||||||
-D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
-D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
||||||
-D LORA_TCXO_GPIO=33
|
-D LORA_TCXO_GPIO=33
|
||||||
|
upload_speed = 115200
|
@ -5,6 +5,10 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/tracker-t1000-e -Isrc/plat
|
|||||||
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
|
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
|
||||||
-DGPS_POWER_TOGGLE
|
-DGPS_POWER_TOGGLE
|
||||||
-DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL=1
|
-DMESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL=1
|
||||||
|
-DMESHTASTIC_EXCLUDE_CANNEDMESSAGES=1
|
||||||
|
-DMESHTASTIC_EXCLUDE_SCREEN=1
|
||||||
|
-DMESHTASTIC_EXCLUDE_DETECTIONSENSOR=1
|
||||||
|
-DMESHTASTIC_EXCLUDE_WIFI=1
|
||||||
board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld
|
board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld
|
||||||
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/tracker-t1000-e>
|
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/tracker-t1000-e>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
|
@ -152,6 +152,8 @@ extern "C" {
|
|||||||
#define T1000X_NTC_PIN (0 + 31) // P0.31/AIN7
|
#define T1000X_NTC_PIN (0 + 31) // P0.31/AIN7
|
||||||
#define T1000X_LUX_PIN (0 + 29) // P0.29/AIN5
|
#define T1000X_LUX_PIN (0 + 29) // P0.29/AIN5
|
||||||
|
|
||||||
|
#define HAS_SCREEN 0
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
[VERSION]
|
[VERSION]
|
||||||
major = 2
|
major = 2
|
||||||
minor = 6
|
minor = 6
|
||||||
build = 5
|
build = 6
|
||||||
|
Loading…
Reference in New Issue
Block a user