mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-17 16:22:48 +00:00
Compare commits
46 Commits
indicator-
...
zps-module
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7435b85a1 | ||
|
|
729d6c576f | ||
|
|
15b84fca01 | ||
|
|
285b30dff0 | ||
|
|
834c3c5cc2 | ||
|
|
25a19b49ad | ||
|
|
a4d96bebfb | ||
|
|
d21d6d2085 | ||
|
|
26c38ffc8e | ||
|
|
237b8908f7 | ||
|
|
06bccef462 | ||
|
|
3120bb8fd7 | ||
|
|
0903ed8232 | ||
|
|
f8ba392a24 | ||
|
|
3dd384dd53 | ||
|
|
2c071a3283 | ||
|
|
596cd7e0b6 | ||
|
|
3f5c30e3b3 | ||
|
|
1a279c6053 | ||
|
|
3d825c51dd | ||
|
|
915f882e1f | ||
|
|
5136c8ba24 | ||
|
|
8b42bf7a95 | ||
|
|
1daf5aad1f | ||
|
|
fe3f14a63e | ||
|
|
7574bfb7cb | ||
|
|
ce75bf4496 | ||
|
|
5ce47045e7 | ||
|
|
57e1725419 | ||
|
|
11309662a9 | ||
|
|
890357d579 | ||
|
|
f413c49555 | ||
|
|
c19f573b49 | ||
|
|
5de61b1a3d | ||
|
|
1c1462e776 | ||
|
|
eb6ef1cbea | ||
|
|
9654f5b218 | ||
|
|
68726a1b0e | ||
|
|
5b62bbe8e6 | ||
|
|
e55084629a | ||
|
|
1691e885f2 | ||
|
|
2d7818797d | ||
|
|
f65e2c639e | ||
|
|
95200e8f6b | ||
|
|
36e8dc74f4 | ||
|
|
78c5309e9a |
238
.github/workflows/pr_tests.yml
vendored
Normal file
238
.github/workflows/pr_tests.yml
vendored
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
name: Tests
|
||||||
|
|
||||||
|
# DISABLED: Changed from automatic PR triggers to manual only
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
reason:
|
||||||
|
description: "Reason for manual test run"
|
||||||
|
required: false
|
||||||
|
default: "Manual test execution"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: tests-${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
actions: read
|
||||||
|
checks: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
native-tests:
|
||||||
|
name: "🧪 Native Tests"
|
||||||
|
if: github.repository == 'meshtastic/firmware'
|
||||||
|
uses: ./.github/workflows/test_native.yml
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
actions: read
|
||||||
|
checks: write
|
||||||
|
|
||||||
|
test-summary:
|
||||||
|
name: "📊 Test Results"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [native-tests]
|
||||||
|
if: always()
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
actions: read
|
||||||
|
checks: write
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Get release version string
|
||||||
|
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||||
|
id: version
|
||||||
|
|
||||||
|
- name: Download test artifacts
|
||||||
|
if: needs.native-tests.result != 'skipped'
|
||||||
|
uses: actions/download-artifact@v5
|
||||||
|
with:
|
||||||
|
name: platformio-test-report-${{ steps.version.outputs.long }}.zip
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: Parse test results and create detailed summary
|
||||||
|
id: test-results
|
||||||
|
run: |
|
||||||
|
echo "## 🧪 Test Results Summary" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Check overall job status first
|
||||||
|
if [[ "${{ needs.native-tests.result }}" == "success" ]]; then
|
||||||
|
echo "✅ **Overall Status**: PASSED" >> $GITHUB_STEP_SUMMARY
|
||||||
|
elif [[ "${{ needs.native-tests.result }}" == "failure" ]]; then
|
||||||
|
echo "❌ **Overall Status**: FAILED" >> $GITHUB_STEP_SUMMARY
|
||||||
|
elif [[ "${{ needs.native-tests.result }}" == "cancelled" ]]; then
|
||||||
|
echo "⏸️ **Overall Status**: CANCELLED" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Tests were cancelled before completion." >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "⚠️ **Overall Status**: SKIPPED" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Tests were skipped." >> $GITHUB_STEP_SUMMARY
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Parse detailed test results if available
|
||||||
|
if [ -f "testreport.xml" ]; then
|
||||||
|
echo "### 🔍 Individual Test Results" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
python3 << 'EOF'
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
import os
|
||||||
|
|
||||||
|
try:
|
||||||
|
tree = ET.parse('testreport.xml')
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
total_tests = 0
|
||||||
|
passed_tests = 0
|
||||||
|
failed_tests = 0
|
||||||
|
skipped_tests = 0
|
||||||
|
|
||||||
|
# Parse testsuite elements
|
||||||
|
for testsuite in root.findall('.//testsuite'):
|
||||||
|
suite_name = testsuite.get('name', 'Unknown')
|
||||||
|
suite_tests = int(testsuite.get('tests', '0'))
|
||||||
|
suite_failures = int(testsuite.get('failures', '0'))
|
||||||
|
suite_errors = int(testsuite.get('errors', '0'))
|
||||||
|
suite_skipped = int(testsuite.get('skipped', '0'))
|
||||||
|
|
||||||
|
total_tests += suite_tests
|
||||||
|
failed_tests += suite_failures + suite_errors
|
||||||
|
skipped_tests += suite_skipped
|
||||||
|
passed_tests += suite_tests - suite_failures - suite_errors - suite_skipped
|
||||||
|
|
||||||
|
if suite_tests > 0:
|
||||||
|
status = "✅" if (suite_failures + suite_errors) == 0 else "❌"
|
||||||
|
print(f"**{status} Test Suite: {suite_name}**")
|
||||||
|
print(f"- Total: {suite_tests}")
|
||||||
|
print(f"- Passed: ✅ {suite_tests - suite_failures - suite_errors - suite_skipped}")
|
||||||
|
print(f"- Failed: ❌ {suite_failures + suite_errors}")
|
||||||
|
if suite_skipped > 0:
|
||||||
|
print(f"- Skipped: ⏭️ {suite_skipped}")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# Show individual test results for failed suites
|
||||||
|
if suite_failures + suite_errors > 0:
|
||||||
|
print("**Failed Tests:**")
|
||||||
|
for testcase in testsuite.findall('testcase'):
|
||||||
|
test_name = testcase.get('name', 'Unknown')
|
||||||
|
failure = testcase.find('failure')
|
||||||
|
error = testcase.find('error')
|
||||||
|
|
||||||
|
if failure is not None:
|
||||||
|
msg = failure.get('message', 'Unknown error')[:100]
|
||||||
|
print(f"- ❌ `{test_name}`: {msg}")
|
||||||
|
elif error is not None:
|
||||||
|
msg = error.get('message', 'Unknown error')[:100]
|
||||||
|
print(f"- ❌ `{test_name}`: ERROR - {msg}")
|
||||||
|
print("")
|
||||||
|
else:
|
||||||
|
# Show passed tests for successful suites
|
||||||
|
passed_count = 0
|
||||||
|
for testcase in testsuite.findall('testcase'):
|
||||||
|
if testcase.find('failure') is None and testcase.find('error') is None:
|
||||||
|
if passed_count < 5: # Limit to first 5 to avoid spam
|
||||||
|
test_name = testcase.get('name', 'Unknown')
|
||||||
|
print(f"- ✅ `{test_name}`: PASSED")
|
||||||
|
passed_count += 1
|
||||||
|
if passed_count > 5:
|
||||||
|
print(f"- ... and {passed_count - 5} more tests passed")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# Summary statistics
|
||||||
|
print("### 📊 Test Statistics")
|
||||||
|
print(f"- **Total Tests**: {total_tests}")
|
||||||
|
print(f"- **Passed**: ✅ {passed_tests}")
|
||||||
|
print(f"- **Failed**: ❌ {failed_tests}")
|
||||||
|
if skipped_tests > 0:
|
||||||
|
print(f"- **Skipped**: ⏭️ {skipped_tests}")
|
||||||
|
|
||||||
|
if failed_tests > 0:
|
||||||
|
print(f"\n❌ **{failed_tests} tests failed out of {total_tests} total**")
|
||||||
|
else:
|
||||||
|
print(f"\n✅ **All {total_tests} tests passed!**")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error parsing test results: {e}")
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
echo "⚠️ **No detailed test report available**" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Test artifacts may not have been generated properly." >> $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "---" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "View detailed logs in the [Actions tab](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
- name: Comment test results on PR
|
||||||
|
if: github.event_name == 'pull_request' && needs.native-tests.result != 'skipped'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
// Read the step summary to use as PR comment
|
||||||
|
let testSummary = "## 🧪 Test Results Summary\n\n";
|
||||||
|
|
||||||
|
if ("${{ needs.native-tests.result }}" === "success") {
|
||||||
|
testSummary += "✅ **All tests passed!**\n\n";
|
||||||
|
} else if ("${{ needs.native-tests.result }}" === "failure") {
|
||||||
|
testSummary += "❌ **Some tests failed.**\n\n";
|
||||||
|
} else {
|
||||||
|
testSummary += "⚠️ **Tests did not complete normally.**\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
testSummary += `View detailed results: [Actions Run](${context.payload.repository.html_url}/actions/runs/${context.runId})\n\n`;
|
||||||
|
testSummary += "---\n";
|
||||||
|
testSummary += "*This comment will be automatically updated when new commits are pushed.*";
|
||||||
|
|
||||||
|
// Find existing comment
|
||||||
|
const comments = await github.rest.issues.listComments({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.issue.number
|
||||||
|
});
|
||||||
|
|
||||||
|
const botComment = comments.data.find(comment =>
|
||||||
|
comment.user.type === 'Bot' &&
|
||||||
|
comment.body.includes('🧪 Test Results Summary')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (botComment) {
|
||||||
|
// Update existing comment
|
||||||
|
await github.rest.issues.updateComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
comment_id: botComment.id,
|
||||||
|
body: testSummary
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Create new comment
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
body: testSummary
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Set overall status
|
||||||
|
run: |
|
||||||
|
if [[ "${{ needs.native-tests.result }}" == "success" ]]; then
|
||||||
|
echo "All tests passed! ✅"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "Some tests failed! ❌"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -4,19 +4,19 @@ cli:
|
|||||||
plugins:
|
plugins:
|
||||||
sources:
|
sources:
|
||||||
- id: trunk
|
- id: trunk
|
||||||
ref: v1.7.1
|
ref: v1.7.2
|
||||||
uri: https://github.com/trunk-io/plugins
|
uri: https://github.com/trunk-io/plugins
|
||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
- checkov@3.2.461
|
- checkov@3.2.465
|
||||||
- renovate@41.71.1
|
- renovate@41.82.10
|
||||||
- prettier@3.6.2
|
- prettier@3.6.2
|
||||||
- trufflehog@3.90.4
|
- trufflehog@3.90.5
|
||||||
- yamllint@1.37.1
|
- yamllint@1.37.1
|
||||||
- bandit@1.8.6
|
- bandit@1.8.6
|
||||||
- trivy@0.64.1
|
- trivy@0.65.0
|
||||||
- taplo@0.9.3
|
- taplo@0.10.0
|
||||||
- ruff@0.12.7
|
- ruff@0.12.10
|
||||||
- isort@6.0.1
|
- isort@6.0.1
|
||||||
- markdownlint@0.45.0
|
- markdownlint@0.45.0
|
||||||
- oxipng@9.1.5
|
- oxipng@9.1.5
|
||||||
@@ -25,7 +25,7 @@ lint:
|
|||||||
- flake8@7.3.0
|
- flake8@7.3.0
|
||||||
- hadolint@2.12.1-beta
|
- hadolint@2.12.1-beta
|
||||||
- shfmt@3.6.0
|
- shfmt@3.6.0
|
||||||
- shellcheck@0.10.0
|
- shellcheck@0.11.0
|
||||||
- black@25.1.0
|
- black@25.1.0
|
||||||
- git-diff-check
|
- git-diff-check
|
||||||
- gitleaks@8.28.0
|
- gitleaks@8.28.0
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ RUN apt-get update && apt-get --no-install-recommends -y install \
|
|||||||
|
|
||||||
# Fetch compiled binary from the builder
|
# Fetch compiled binary from the builder
|
||||||
COPY --from=builder /tmp/firmware/release/meshtasticd /usr/bin/
|
COPY --from=builder /tmp/firmware/release/meshtasticd /usr/bin/
|
||||||
COPY --from=builder /tmp/web /usr/share/meshtasticd/
|
COPY --from=builder /tmp/web /usr/share/meshtasticd/web/
|
||||||
# Copy config templates
|
# Copy config templates
|
||||||
COPY ./bin/config.d /etc/meshtasticd/available.d
|
COPY ./bin/config.d /etc/meshtasticd/available.d
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
[portduino_base]
|
[portduino_base]
|
||||||
platform =
|
platform =
|
||||||
# renovate: datasource=git-refs depName=platform-native packageName=https://github.com/meshtastic/platform-native gitBranch=develop
|
# renovate: datasource=git-refs depName=platform-native packageName=https://github.com/meshtastic/platform-native gitBranch=develop
|
||||||
https://github.com/meshtastic/platform-native/archive/6cb7a455b440dd0738e8ed74a18136ed5cf7ea63.zip
|
https://github.com/meshtastic/platform-native/archive/37d986499ce24511952d7146db72d667c6bdaff7.zip
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
|
|||||||
@@ -10,12 +10,3 @@ Lora:
|
|||||||
DIO2_AS_RF_SWITCH: true
|
DIO2_AS_RF_SWITCH: true
|
||||||
spidev: spidev0.0
|
spidev: spidev0.0
|
||||||
# CS: 8
|
# CS: 8
|
||||||
|
|
||||||
|
|
||||||
### RAK13300in Slot 2 pins
|
|
||||||
# IRQ: 18 #IO6
|
|
||||||
# Reset: 24 # IO4
|
|
||||||
# Busy: 19 # IO5
|
|
||||||
# # Ant_sw: 23 # IO3
|
|
||||||
# spidev: spidev0.1
|
|
||||||
# # CS: 7
|
|
||||||
8
bin/config.d/lora-RAK6421-13300-slot2.yaml
Normal file
8
bin/config.d/lora-RAK6421-13300-slot2.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Lora:
|
||||||
|
### RAK13300in Slot 2 pins
|
||||||
|
IRQ: 18 #IO6
|
||||||
|
Reset: 24 # IO4
|
||||||
|
Busy: 19 # IO5
|
||||||
|
# Ant_sw: 23 # IO3
|
||||||
|
spidev: spidev0.1
|
||||||
|
# CS: 7
|
||||||
54
boards/heltec_mesh_solar.json
Normal file
54
boards/heltec_mesh_solar.json
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"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"],
|
||||||
|
["0x239A", "0x0071"]
|
||||||
|
],
|
||||||
|
"usb_product": "HT-n5262",
|
||||||
|
"mcu": "nrf52840",
|
||||||
|
"variant": "heltec_mesh_solar",
|
||||||
|
"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/meshsolar/",
|
||||||
|
"vendor": "Heltec"
|
||||||
|
}
|
||||||
52
boards/meshtiny.json
Normal file
52
boards/meshtiny.json
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "nrf52840_s140_v6.ld"
|
||||||
|
},
|
||||||
|
"core": "nRF5",
|
||||||
|
"cpu": "cortex-m4",
|
||||||
|
"extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA",
|
||||||
|
"f_cpu": "64000000L",
|
||||||
|
"hwids": [
|
||||||
|
["0x239A", "0x8029"],
|
||||||
|
["0x239A", "0x0029"],
|
||||||
|
["0x239A", "0x002A"],
|
||||||
|
["0x239A", "0x802A"]
|
||||||
|
],
|
||||||
|
"usb_product": "MeshTiny",
|
||||||
|
"mcu": "nrf52840",
|
||||||
|
"variant": "meshtiny",
|
||||||
|
"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",
|
||||||
|
"svd_path": "nrf52840.svd",
|
||||||
|
"openocd_target": "nrf52840-mdk-rs"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino", "freertos"],
|
||||||
|
"name": "MeshTiny",
|
||||||
|
"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://github.com/meshtastic/firmware",
|
||||||
|
"vendor": "MTools Tec"
|
||||||
|
}
|
||||||
@@ -48,6 +48,7 @@ build_flags = -Wno-missing-field-initializers
|
|||||||
-DRADIOLIB_EXCLUDE_APRS=1
|
-DRADIOLIB_EXCLUDE_APRS=1
|
||||||
-DRADIOLIB_EXCLUDE_LORAWAN=1
|
-DRADIOLIB_EXCLUDE_LORAWAN=1
|
||||||
-DMESHTASTIC_EXCLUDE_DROPZONE=1
|
-DMESHTASTIC_EXCLUDE_DROPZONE=1
|
||||||
|
-DMESHTASTIC_EXCLUDE_ZPS=1
|
||||||
-DMESHTASTIC_EXCLUDE_REMOTEHARDWARE=1
|
-DMESHTASTIC_EXCLUDE_REMOTEHARDWARE=1
|
||||||
-DMESHTASTIC_EXCLUDE_HEALTH_TELEMETRY=1
|
-DMESHTASTIC_EXCLUDE_HEALTH_TELEMETRY=1
|
||||||
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
|
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
|
||||||
@@ -60,7 +61,7 @@ monitor_speed = 115200
|
|||||||
monitor_filters = direct
|
monitor_filters = direct
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master
|
||||||
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/0119501e9983bd894830b02f545c377ee08d66fe.zip
|
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/9573abb64dc9c94f3051348f2bf4fc5cedf03c22.zip
|
||||||
# renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master
|
||||||
https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip
|
https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip
|
||||||
# renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master
|
||||||
@@ -118,7 +119,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/0cd108ff783539e41ef38258ba2784ab3b1bdc97.zip
|
https://github.com/meshtastic/device-ui/archive/a3e0e1be372d069f47b4c19d718f5267251744d7.zip
|
||||||
|
|
||||||
; Common libs for environmental measurements in telemetry module
|
; Common libs for environmental measurements in telemetry module
|
||||||
[environmental_base]
|
[environmental_base]
|
||||||
|
|||||||
Submodule protobufs updated: 5dd723fe6f...8985852d75
@@ -681,6 +681,8 @@ bool Power::setup()
|
|||||||
found = true;
|
found = true;
|
||||||
} else if (lipoChargerInit()) {
|
} else if (lipoChargerInit()) {
|
||||||
found = true;
|
found = true;
|
||||||
|
} else if (meshSolarInit()) {
|
||||||
|
found = true;
|
||||||
} else if (analogInit()) {
|
} else if (analogInit()) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
@@ -1450,3 +1452,75 @@ bool Power::lipoChargerInit()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HELTEC_MESH_SOLAR
|
||||||
|
#include "meshSolarApp.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* meshSolar class for an SMBUS battery sensor.
|
||||||
|
*/
|
||||||
|
class meshSolarBatteryLevel : public HasBatteryLevel
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Init the I2C meshSolar battery level sensor
|
||||||
|
*/
|
||||||
|
bool runOnce()
|
||||||
|
{
|
||||||
|
meshSolarStart();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Battery state of charge, from 0 to 100 or -1 for unknown
|
||||||
|
*/
|
||||||
|
virtual int getBatteryPercent() override { return meshSolarGetBatteryPercent(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw voltage of the battery in millivolts, or NAN if unknown
|
||||||
|
*/
|
||||||
|
virtual uint16_t getBattVoltage() override { return meshSolarGetBattVoltage(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true if there is a battery installed in this unit
|
||||||
|
*/
|
||||||
|
virtual bool isBatteryConnect() override { return meshSolarIsBatteryConnect(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true if there is an external power source detected
|
||||||
|
*/
|
||||||
|
virtual bool isVbusIn() override { return meshSolarIsVbusIn();}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true if the battery is currently charging
|
||||||
|
*/
|
||||||
|
virtual bool isCharging() override { return meshSolarIsCharging(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
meshSolarBatteryLevel meshSolarLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init the meshSolar battery level sensor
|
||||||
|
*/
|
||||||
|
bool Power::meshSolarInit()
|
||||||
|
{
|
||||||
|
bool result = meshSolarLevel.runOnce();
|
||||||
|
LOG_DEBUG("Power::meshSolarInit mesh solar sensor is %s", result ? "ready" : "not ready yet");
|
||||||
|
if (!result)
|
||||||
|
return false;
|
||||||
|
batteryLevel = &meshSolarLevel;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
/**
|
||||||
|
* The meshSolar battery level sensor is unavailable - default to AnalogBatteryLevel
|
||||||
|
*/
|
||||||
|
bool Power::meshSolarInit()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -64,6 +64,14 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con
|
|||||||
|
|
||||||
int32_t SerialConsole::runOnce()
|
int32_t SerialConsole::runOnce()
|
||||||
{
|
{
|
||||||
|
#ifdef HELTEC_MESH_SOLAR
|
||||||
|
//After enabling the mesh solar serial port module configuration, command processing is handled by the serial port module.
|
||||||
|
if(moduleConfig.serial.enabled && moduleConfig.serial.override_console_serial_port
|
||||||
|
&& moduleConfig.serial.mode==meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MS_CONFIG)
|
||||||
|
{
|
||||||
|
return 250;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return runOncePart();
|
return runOncePart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// OLED & Input
|
// OLED & Input
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
#if defined(SEEED_WIO_TRACKER_L1)
|
#if defined(SEEED_WIO_TRACKER_L1) && !defined(SEEED_WIO_TRACKER_L1_EINK)
|
||||||
#define SSD1306_ADDRESS 0x3D
|
#define SSD1306_ADDRESS 0x3D
|
||||||
#define USE_SH1106
|
#define USE_SH1106
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -79,7 +79,8 @@ class ScanI2C
|
|||||||
BQ27220,
|
BQ27220,
|
||||||
LTR553ALS,
|
LTR553ALS,
|
||||||
BHI260AP,
|
BHI260AP,
|
||||||
BMM150
|
BMM150,
|
||||||
|
DRV2605
|
||||||
} DeviceType;
|
} DeviceType;
|
||||||
|
|
||||||
// typedef uint8_t DeviceAddress;
|
// typedef uint8_t DeviceAddress;
|
||||||
|
|||||||
@@ -483,8 +483,14 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
type = MLX90614;
|
type = MLX90614;
|
||||||
logFoundDevice("MLX90614", (uint8_t)addr.address);
|
logFoundDevice("MLX90614", (uint8_t)addr.address);
|
||||||
} else {
|
} else {
|
||||||
type = MPR121KB;
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); // DRV2605_REG_STATUS
|
||||||
logFoundDevice("MPR121KB", (uint8_t)addr.address);
|
if (registerValue == 0xe0) {
|
||||||
|
type = DRV2605;
|
||||||
|
logFoundDevice("DRV2605", (uint8_t)addr.address);
|
||||||
|
} else {
|
||||||
|
type = MPR121KB;
|
||||||
|
logFoundDevice("MPR121KB", (uint8_t)addr.address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -67,20 +67,28 @@ bool EInkDisplay::forceDisplay(uint32_t msecLimit)
|
|||||||
|
|
||||||
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
// FIXME - only draw bits have changed (use backbuf similar to the other displays)
|
||||||
const bool flipped = config.display.flip_screen;
|
const bool flipped = config.display.flip_screen;
|
||||||
|
// HACK for L1 EInk
|
||||||
|
#if defined(SEEED_WIO_TRACKER_L1_EINK)
|
||||||
|
// For SEEED_WIO_TRACKER_L1_EINK, setRotation(3) is correct but mirrored; flip both axes
|
||||||
|
for (uint32_t y = 0; y < displayHeight; y++) {
|
||||||
|
for (uint32_t x = 0; x < displayWidth; x++) {
|
||||||
|
auto b = buffer[x + (y / 8) * displayWidth];
|
||||||
|
auto isset = b & (1 << (y & 7));
|
||||||
|
adafruitDisplay->drawPixel((displayWidth - 1) - x, (displayHeight - 1) - y, isset ? GxEPD_BLACK : GxEPD_WHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
for (uint32_t y = 0; y < displayHeight; y++) {
|
for (uint32_t y = 0; y < displayHeight; y++) {
|
||||||
for (uint32_t x = 0; x < displayWidth; x++) {
|
for (uint32_t x = 0; x < displayWidth; x++) {
|
||||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficient
|
|
||||||
auto b = buffer[x + (y / 8) * displayWidth];
|
auto b = buffer[x + (y / 8) * displayWidth];
|
||||||
auto isset = b & (1 << (y & 7));
|
auto isset = b & (1 << (y & 7));
|
||||||
|
|
||||||
// Handle flip here, rather than with setRotation(),
|
|
||||||
// Avoids issues when display width is not a multiple of 8
|
|
||||||
if (flipped)
|
if (flipped)
|
||||||
adafruitDisplay->drawPixel((displayWidth - 1) - x, (displayHeight - 1) - y, isset ? GxEPD_BLACK : GxEPD_WHITE);
|
adafruitDisplay->drawPixel((displayWidth - 1) - x, (displayHeight - 1) - y, isset ? GxEPD_BLACK : GxEPD_WHITE);
|
||||||
else
|
else
|
||||||
adafruitDisplay->drawPixel(x, y, isset ? GxEPD_BLACK : GxEPD_WHITE);
|
adafruitDisplay->drawPixel(x, y, isset ? GxEPD_BLACK : GxEPD_WHITE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Trigger the refresh in GxEPD2
|
// Trigger the refresh in GxEPD2
|
||||||
LOG_DEBUG("Update E-Paper");
|
LOG_DEBUG("Update E-Paper");
|
||||||
@@ -235,7 +243,7 @@ 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)
|
#elif defined(HELTEC_MESH_POCKET) || defined(SEEED_WIO_TRACKER_L1_EINK)
|
||||||
{
|
{
|
||||||
spi1 = &SPI1;
|
spi1 = &SPI1;
|
||||||
spi1->begin();
|
spi1->begin();
|
||||||
@@ -249,6 +257,7 @@ bool EInkDisplay::connect()
|
|||||||
// Init GxEPD2
|
// Init GxEPD2
|
||||||
adafruitDisplay->init();
|
adafruitDisplay->init();
|
||||||
adafruitDisplay->setRotation(3);
|
adafruitDisplay->setRotation(3);
|
||||||
|
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
||||||
}
|
}
|
||||||
#elif defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213)
|
#elif defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213)
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class EInkDisplay : public OLEDDisplay
|
|||||||
SPIClass *hspi = NULL;
|
SPIClass *hspi = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HELTEC_MESH_POCKET)
|
#if defined(HELTEC_MESH_POCKET) || defined(SEEED_WIO_TRACKER_L1_EINK)
|
||||||
SPIClass *spi1 = NULL;
|
SPIClass *spi1 = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
|||||||
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
|
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
|
||||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7789_CS) || \
|
#elif defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7789_CS) || \
|
||||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS)
|
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||||
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
||||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||||
#elif defined(USE_EINK) && !defined(USE_EINK_DYNAMICDISPLAY)
|
#elif defined(USE_EINK) && !defined(USE_EINK_DYNAMICDISPLAY)
|
||||||
@@ -550,7 +550,7 @@ void Screen::setup()
|
|||||||
#else
|
#else
|
||||||
if (!config.display.flip_screen) {
|
if (!config.display.flip_screen) {
|
||||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
|
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
|
||||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS)
|
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||||
static_cast<TFTDisplay *>(dispdev)->flipScreenVertically();
|
static_cast<TFTDisplay *>(dispdev)->flipScreenVertically();
|
||||||
#elif defined(USE_ST7789)
|
#elif defined(USE_ST7789)
|
||||||
static_cast<ST7789Spi *>(dispdev)->flipScreenVertically();
|
static_cast<ST7789Spi *>(dispdev)->flipScreenVertically();
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS)) && \
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS)) && \
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
// The screen is bigger so use bigger fonts
|
// The screen is bigger so use bigger fonts
|
||||||
#define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19
|
#define FONT_SMALL FONT_MEDIUM_LOCAL // Height: 19
|
||||||
|
|||||||
@@ -562,6 +562,91 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
|
|
||||||
static LGFX *tft = nullptr;
|
static LGFX *tft = nullptr;
|
||||||
|
|
||||||
|
#elif defined(ST7796_CS)
|
||||||
|
#include <LovyanGFX.hpp> // Graphics and font library for ST7796 driver chip
|
||||||
|
|
||||||
|
class LGFX : public lgfx::LGFX_Device
|
||||||
|
{
|
||||||
|
lgfx::Panel_ST7796 _panel_instance;
|
||||||
|
lgfx::Bus_SPI _bus_instance;
|
||||||
|
lgfx::Light_PWM _light_instance;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LGFX(void)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
auto cfg = _bus_instance.config();
|
||||||
|
|
||||||
|
// SPI
|
||||||
|
cfg.spi_host = ST7796_SPI_HOST;
|
||||||
|
cfg.spi_mode = 0;
|
||||||
|
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
||||||
|
// 80MHz by an integer)
|
||||||
|
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
||||||
|
cfg.spi_3wire = false;
|
||||||
|
cfg.use_lock = true; // Set to true to use transaction locking
|
||||||
|
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||||
|
// SPI_DMA_CH_AUTO=auto setting)
|
||||||
|
cfg.pin_sclk = ST7796_SCK; // Set SPI SCLK pin number
|
||||||
|
cfg.pin_mosi = ST7796_SDA; // Set SPI MOSI pin number
|
||||||
|
cfg.pin_miso = ST7796_MISO; // Set SPI MISO pin number (-1 = disable)
|
||||||
|
cfg.pin_dc = ST7796_RS; // Set SPI DC pin number (-1 = disable)
|
||||||
|
|
||||||
|
_bus_instance.config(cfg); // applies the set value to the bus.
|
||||||
|
_panel_instance.setBus(&_bus_instance); // set the bus on the panel.
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Set the display panel control.
|
||||||
|
auto cfg = _panel_instance.config(); // Gets a structure for display panel settings.
|
||||||
|
|
||||||
|
cfg.pin_cs = ST7796_CS; // Pin number where CS is connected (-1 = disable)
|
||||||
|
cfg.pin_rst = ST7796_RESET; // Pin number where RST is connected (-1 = disable)
|
||||||
|
cfg.pin_busy = ST7796_BUSY; // Pin number where BUSY is connected (-1 = disable)
|
||||||
|
|
||||||
|
// cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
|
||||||
|
// cfg.memory_height = TFT_HEIGHT; // Maximum height supported by the driver IC
|
||||||
|
cfg.panel_width = TFT_WIDTH; // actual displayable width
|
||||||
|
cfg.panel_height = TFT_HEIGHT; // actual displayable height
|
||||||
|
cfg.offset_x = TFT_OFFSET_X; // Panel offset amount in X direction
|
||||||
|
cfg.offset_y = TFT_OFFSET_Y; // Panel offset amount in Y direction
|
||||||
|
cfg.offset_rotation = TFT_OFFSET_ROTATION; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||||
|
#ifdef TFT_DUMMY_READ_PIXELS
|
||||||
|
cfg.dummy_read_pixel = TFT_DUMMY_READ_PIXELS; // Number of bits for dummy read before pixel readout
|
||||||
|
#else
|
||||||
|
cfg.dummy_read_pixel = 8; // Number of bits for dummy read before pixel readout
|
||||||
|
#endif
|
||||||
|
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
|
||||||
|
cfg.readable = true; // Set to true if data can be read
|
||||||
|
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
|
||||||
|
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||||
|
cfg.dlen_16bit =
|
||||||
|
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||||
|
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||||
|
|
||||||
|
_panel_instance.config(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ST7796_BL
|
||||||
|
// Set the backlight control. (delete if not necessary)
|
||||||
|
{
|
||||||
|
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
|
||||||
|
|
||||||
|
cfg.pin_bl = ST7796_BL; // Pin number to which the backlight is connected
|
||||||
|
cfg.invert = false; // true to invert the brightness of the backlight
|
||||||
|
cfg.freq = 44100;
|
||||||
|
cfg.pwm_channel = 7;
|
||||||
|
|
||||||
|
_light_instance.config(cfg);
|
||||||
|
_panel_instance.setLight(&_light_instance); // Set the backlight on the panel.
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setPanel(&_panel_instance); // Sets the panel to use.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static LGFX *tft = nullptr;
|
||||||
|
|
||||||
#elif defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER)
|
#elif defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER)
|
||||||
|
|
||||||
#include <LovyanGFX.hpp> // Graphics and font library for ILI9341/ILI9342 driver chip
|
#include <LovyanGFX.hpp> // Graphics and font library for ILI9341/ILI9342 driver chip
|
||||||
@@ -667,15 +752,19 @@ static LGFX *tft = nullptr;
|
|||||||
static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h
|
static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h
|
||||||
#elif ARCH_PORTDUINO
|
#elif ARCH_PORTDUINO
|
||||||
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||||
|
#if defined(LGFX_SDL)
|
||||||
|
#include <lgfx/v1/platforms/sdl/Panel_sdl.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
class LGFX : public lgfx::LGFX_Device
|
class LGFX : public lgfx::LGFX_Device
|
||||||
{
|
{
|
||||||
lgfx::Panel_Device *_panel_instance;
|
|
||||||
lgfx::Bus_SPI _bus_instance;
|
lgfx::Bus_SPI _bus_instance;
|
||||||
|
|
||||||
lgfx::ITouch *_touch_instance;
|
lgfx::ITouch *_touch_instance;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
lgfx::Panel_Device *_panel_instance;
|
||||||
|
|
||||||
LGFX(void)
|
LGFX(void)
|
||||||
{
|
{
|
||||||
if (settingsMap[displayPanel] == st7789)
|
if (settingsMap[displayPanel] == st7789)
|
||||||
@@ -694,6 +783,11 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
_panel_instance = new lgfx::Panel_ILI9488;
|
_panel_instance = new lgfx::Panel_ILI9488;
|
||||||
else if (settingsMap[displayPanel] == hx8357d)
|
else if (settingsMap[displayPanel] == hx8357d)
|
||||||
_panel_instance = new lgfx::Panel_HX8357D;
|
_panel_instance = new lgfx::Panel_HX8357D;
|
||||||
|
#if defined(LGFX_SDL)
|
||||||
|
else if (settingsMap[displayPanel] == x11) {
|
||||||
|
_panel_instance = new lgfx::Panel_sdl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
else {
|
else {
|
||||||
_panel_instance = new lgfx::Panel_NULL;
|
_panel_instance = new lgfx::Panel_NULL;
|
||||||
LOG_ERROR("Unknown display panel configured!");
|
LOG_ERROR("Unknown display panel configured!");
|
||||||
@@ -754,7 +848,13 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
_touch_instance->config(touch_cfg);
|
_touch_instance->config(touch_cfg);
|
||||||
_panel_instance->setTouch(_touch_instance);
|
_panel_instance->setTouch(_touch_instance);
|
||||||
}
|
}
|
||||||
|
#if defined(LGFX_SDL)
|
||||||
|
if (settingsMap[displayPanel] == x11) {
|
||||||
|
lgfx::Panel_sdl *sdl_panel_ = (lgfx::Panel_sdl *)_panel_instance;
|
||||||
|
sdl_panel_->setup();
|
||||||
|
sdl_panel_->addKeyCodeMapping(SDLK_RETURN, SDL_SCANCODE_KP_ENTER);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
setPanel(_panel_instance); // Sets the panel to use.
|
setPanel(_panel_instance); // Sets the panel to use.
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -849,9 +949,29 @@ static LGFX *tft = nullptr;
|
|||||||
#include <lgfx/v1/platforms/esp32s3/Bus_RGB.hpp>
|
#include <lgfx/v1/platforms/esp32s3/Bus_RGB.hpp>
|
||||||
#include <lgfx/v1/platforms/esp32s3/Panel_RGB.hpp>
|
#include <lgfx/v1/platforms/esp32s3/Panel_RGB.hpp>
|
||||||
|
|
||||||
|
class PanelInit_ST7701 : public lgfx::Panel_ST7701
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const uint8_t *getInitCommands(uint8_t listno) const override
|
||||||
|
{
|
||||||
|
// 180 degree hw rotation: vertical flip, horizontal flip
|
||||||
|
static constexpr const uint8_t list1[] = {0x36, 1, 0x10, // MADCTL for vertical flip
|
||||||
|
0xFF, 5, 0x77, 0x01, 0x00, 0x00, 0x10, // Command2 BK0 SEL
|
||||||
|
0xC7, 1, 0x04, // SDIR: X-direction Control (Horizontal Flip)
|
||||||
|
0xFF, 5, 0x77, 0x01, 0x00, 0x00, 0x00, // Command2 BK0 DIS
|
||||||
|
0xFF, 0xFF};
|
||||||
|
switch (listno) {
|
||||||
|
case 1:
|
||||||
|
return list1;
|
||||||
|
default:
|
||||||
|
return lgfx::Panel_ST7701::getInitCommands(listno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class LGFX : public lgfx::LGFX_Device
|
class LGFX : public lgfx::LGFX_Device
|
||||||
{
|
{
|
||||||
lgfx::Panel_ST7701 _panel_instance;
|
PanelInit_ST7701 _panel_instance;
|
||||||
lgfx::Bus_RGB _bus_instance;
|
lgfx::Bus_RGB _bus_instance;
|
||||||
lgfx::Light_PWM _light_instance;
|
lgfx::Light_PWM _light_instance;
|
||||||
lgfx::Touch_FT5x06 _touch_instance;
|
lgfx::Touch_FT5x06 _touch_instance;
|
||||||
@@ -962,8 +1082,9 @@ static LGFX *tft = nullptr;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(ST7789_CS) || defined(ST7796_CS) || defined(ILI9341_DRIVER) || \
|
||||||
defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST72xx_DE) || (ARCH_PORTDUINO && HAS_SCREEN != 0)
|
defined(ILI9342_DRIVER) || defined(RAK14014) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST72xx_DE) || \
|
||||||
|
(ARCH_PORTDUINO && HAS_SCREEN != 0)
|
||||||
#include "SPILock.h"
|
#include "SPILock.h"
|
||||||
#include "TFTDisplay.h"
|
#include "TFTDisplay.h"
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
@@ -1012,32 +1133,140 @@ void TFTDisplay::display(bool fromBlank)
|
|||||||
{
|
{
|
||||||
if (fromBlank)
|
if (fromBlank)
|
||||||
tft->fillScreen(TFT_BLACK);
|
tft->fillScreen(TFT_BLACK);
|
||||||
// tft->clear();
|
|
||||||
concurrency::LockGuard g(spiLock);
|
concurrency::LockGuard g(spiLock);
|
||||||
|
|
||||||
uint16_t x, y;
|
uint32_t x, y;
|
||||||
|
uint32_t y_byteIndex;
|
||||||
|
uint8_t y_byteMask;
|
||||||
|
uint32_t x_FirstPixelUpdate;
|
||||||
|
uint32_t x_LastPixelUpdate;
|
||||||
|
bool isset, dblbuf_isset;
|
||||||
|
uint16_t colorTftMesh, colorTftBlack;
|
||||||
|
bool somethingChanged = false;
|
||||||
|
|
||||||
for (y = 0; y < displayHeight; y++) {
|
// Store colors byte-reversed so that TFT_eSPI doesn't have to swap bytes in a separate step
|
||||||
for (x = 0; x < displayWidth; x++) {
|
colorTftMesh = (TFT_MESH >> 8) | ((TFT_MESH & 0xFF) << 8);
|
||||||
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
colorTftBlack = (TFT_BLACK >> 8) | ((TFT_BLACK & 0xFF) << 8);
|
||||||
|
|
||||||
|
y = 0;
|
||||||
|
while (y < displayHeight) {
|
||||||
|
y_byteIndex = (y / 8) * displayWidth;
|
||||||
|
y_byteMask = (1 << (y & 7));
|
||||||
|
|
||||||
|
// Step 1: Do a quick scan of 8 rows together. This allows fast-forwarding over unchanged screen areas.
|
||||||
|
if (y_byteMask == 1) {
|
||||||
if (!fromBlank) {
|
if (!fromBlank) {
|
||||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
for (x = 0; x < displayWidth; x++) {
|
||||||
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
if (buffer[x + y_byteIndex] != buffer_back[x + y_byteIndex])
|
||||||
if (isset != dblbuf_isset) {
|
break;
|
||||||
tft->drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
|
|
||||||
}
|
}
|
||||||
} else if (isset) {
|
} else {
|
||||||
tft->drawPixel(x, y, TFT_MESH);
|
for (x = 0; x < displayWidth; x++) {
|
||||||
|
if (buffer[x + y_byteIndex] != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x >= displayWidth) {
|
||||||
|
// No changed pixels found in these 8 rows, fast-forward to the next 8
|
||||||
|
y = y + 8;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Step 2: Scan each of the 8 rows individually. Find the first pixel in each row that needs updating
|
||||||
|
for (x_FirstPixelUpdate = 0; x_FirstPixelUpdate < displayWidth; x_FirstPixelUpdate++) {
|
||||||
|
isset = buffer[x_FirstPixelUpdate + y_byteIndex] & y_byteMask;
|
||||||
|
|
||||||
|
if (!fromBlank) {
|
||||||
|
// get src pixel in the page based ordering the OLED lib uses
|
||||||
|
dblbuf_isset = buffer_back[x_FirstPixelUpdate + y_byteIndex] & y_byteMask;
|
||||||
|
if (isset != dblbuf_isset) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (isset) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Did we find a pixel that needs updating on this row?
|
||||||
|
if (x_FirstPixelUpdate < displayWidth) {
|
||||||
|
|
||||||
|
// Quickly write out the first changed pixel (saves another array lookup)
|
||||||
|
linePixelBuffer[x_FirstPixelUpdate] = isset ? colorTftMesh : colorTftBlack;
|
||||||
|
x_LastPixelUpdate = x_FirstPixelUpdate;
|
||||||
|
|
||||||
|
// Step 3: copy all remaining pixels in this row into the pixel line buffer,
|
||||||
|
// while also recording the last pixel in the row that needs updating
|
||||||
|
for (x = x_FirstPixelUpdate + 1; x < displayWidth; x++) {
|
||||||
|
isset = buffer[x + y_byteIndex] & y_byteMask;
|
||||||
|
linePixelBuffer[x] = isset ? colorTftMesh : colorTftBlack;
|
||||||
|
|
||||||
|
if (!fromBlank) {
|
||||||
|
dblbuf_isset = buffer_back[x + y_byteIndex] & y_byteMask;
|
||||||
|
if (isset != dblbuf_isset) {
|
||||||
|
x_LastPixelUpdate = x;
|
||||||
|
}
|
||||||
|
} else if (isset) {
|
||||||
|
x_LastPixelUpdate = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Send the changed pixels on this line to the screen as a single block transfer.
|
||||||
|
// This function accepts pixel data MSB first so it can dump the memory straight out the SPI port.
|
||||||
|
tft->pushRect(x_FirstPixelUpdate, y, (x_LastPixelUpdate - x_FirstPixelUpdate + 1), 1,
|
||||||
|
&linePixelBuffer[x_FirstPixelUpdate]);
|
||||||
|
|
||||||
|
somethingChanged = true;
|
||||||
|
}
|
||||||
|
y++;
|
||||||
}
|
}
|
||||||
// Copy the Buffer to the Back Buffer
|
// Copy the Buffer to the Back Buffer
|
||||||
for (y = 0; y < (displayHeight / 8); y++) {
|
if (somethingChanged)
|
||||||
for (x = 0; x < displayWidth; x++) {
|
memcpy(buffer_back, buffer, displayBufferSize);
|
||||||
uint16_t pos = x + y * displayWidth;
|
}
|
||||||
buffer_back[pos] = buffer[pos];
|
|
||||||
|
void TFTDisplay::sdlLoop()
|
||||||
|
{
|
||||||
|
#if defined(LGFX_SDL)
|
||||||
|
static int lastPressed = 0;
|
||||||
|
static int shuttingDown = false;
|
||||||
|
if (settingsMap[displayPanel] == x11) {
|
||||||
|
lgfx::Panel_sdl *sdl_panel_ = (lgfx::Panel_sdl *)tft->_panel_instance;
|
||||||
|
if (sdl_panel_->loop() && !shuttingDown) {
|
||||||
|
LOG_WARN("Window Closed!");
|
||||||
|
InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_SHUTDOWN, .kbchar = 0, .touchX = 0, .touchY = 0};
|
||||||
|
inputBroker->injectInputEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// debounce
|
||||||
|
if (lastPressed != 0 && !lgfx::v1::gpio_in(lastPressed))
|
||||||
|
return;
|
||||||
|
if (!lgfx::v1::gpio_in(37)) {
|
||||||
|
lastPressed = 37;
|
||||||
|
InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_RIGHT, .kbchar = 0, .touchX = 0, .touchY = 0};
|
||||||
|
inputBroker->injectInputEvent(&event);
|
||||||
|
} else if (!lgfx::v1::gpio_in(36)) {
|
||||||
|
lastPressed = 36;
|
||||||
|
InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_UP, .kbchar = 0, .touchX = 0, .touchY = 0};
|
||||||
|
inputBroker->injectInputEvent(&event);
|
||||||
|
} else if (!lgfx::v1::gpio_in(38)) {
|
||||||
|
lastPressed = 38;
|
||||||
|
InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_DOWN, .kbchar = 0, .touchX = 0, .touchY = 0};
|
||||||
|
inputBroker->injectInputEvent(&event);
|
||||||
|
} else if (!lgfx::v1::gpio_in(39)) {
|
||||||
|
lastPressed = 39;
|
||||||
|
InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_LEFT, .kbchar = 0, .touchX = 0, .touchY = 0};
|
||||||
|
inputBroker->injectInputEvent(&event);
|
||||||
|
} else if (!lgfx::v1::gpio_in(SDL_SCANCODE_KP_ENTER)) {
|
||||||
|
lastPressed = SDL_SCANCODE_KP_ENTER;
|
||||||
|
InputEvent event = {.inputEvent = (input_broker_event)INPUT_BROKER_SELECT, .kbchar = 0, .touchX = 0, .touchY = 0};
|
||||||
|
inputBroker->injectInputEvent(&event);
|
||||||
|
} else {
|
||||||
|
lastPressed = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a command to the display (low level function)
|
// Send a command to the display (low level function)
|
||||||
@@ -1184,15 +1413,23 @@ bool TFTDisplay::connect()
|
|||||||
attachInterrupt(digitalPinToInterrupt(SCREEN_TOUCH_INT), rak14014_tpIntHandle, FALLING);
|
attachInterrupt(digitalPinToInterrupt(SCREEN_TOUCH_INT), rak14014_tpIntHandle, FALLING);
|
||||||
#elif defined(T_DECK) || defined(PICOMPUTER_S3) || defined(CHATTER_2)
|
#elif defined(T_DECK) || defined(PICOMPUTER_S3) || defined(CHATTER_2)
|
||||||
tft->setRotation(1); // T-Deck has the TFT in landscape
|
tft->setRotation(1); // T-Deck has the TFT in landscape
|
||||||
#elif defined(T_WATCH_S3) || defined(SENSECAP_INDICATOR)
|
#elif defined(T_WATCH_S3)
|
||||||
tft->setRotation(2); // T-Watch S3 left-handed orientation
|
tft->setRotation(2); // T-Watch S3 left-handed orientation
|
||||||
#elif ARCH_PORTDUINO
|
#elif ARCH_PORTDUINO || defined(SENSECAP_INDICATOR) || defined(T_LORA_PAGER)
|
||||||
tft->setRotation(0); // use config.yaml to set rotation
|
tft->setRotation(0); // use config.yaml to set rotation
|
||||||
#else
|
#else
|
||||||
tft->setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
tft->setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
|
||||||
#endif
|
#endif
|
||||||
tft->fillScreen(TFT_BLACK);
|
tft->fillScreen(TFT_BLACK);
|
||||||
|
|
||||||
|
if (this->linePixelBuffer == NULL) {
|
||||||
|
this->linePixelBuffer = (uint16_t *)malloc(sizeof(uint16_t) * displayWidth);
|
||||||
|
|
||||||
|
if (!this->linePixelBuffer) {
|
||||||
|
LOG_ERROR("Not enough memory to create TFT line buffer\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class TFTDisplay : public OLEDDisplay
|
|||||||
// Write the buffer to the display memory
|
// Write the buffer to the display memory
|
||||||
virtual void display() override { display(false); };
|
virtual void display() override { display(false); };
|
||||||
virtual void display(bool fromBlank);
|
virtual void display(bool fromBlank);
|
||||||
|
void sdlLoop();
|
||||||
|
|
||||||
// Turn the display upside down
|
// Turn the display upside down
|
||||||
virtual void flipScreenVertically();
|
virtual void flipScreenVertically();
|
||||||
@@ -57,4 +58,6 @@ class TFTDisplay : public OLEDDisplay
|
|||||||
|
|
||||||
// Connect to the display
|
// Connect to the display
|
||||||
virtual bool connect() override;
|
virtual bool connect() override;
|
||||||
|
|
||||||
|
uint16_t *linePixelBuffer = nullptr;
|
||||||
};
|
};
|
||||||
@@ -94,7 +94,8 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
|
|||||||
if (!Throttle::isWithinTimespanMs(storeForwardModule->lastHeartbeat,
|
if (!Throttle::isWithinTimespanMs(storeForwardModule->lastHeartbeat,
|
||||||
(storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit
|
(storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || ARCH_PORTDUINO) && \
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
|
||||||
|
ARCH_PORTDUINO) && \
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12,
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12,
|
||||||
8, imgQuestionL1);
|
8, imgQuestionL1);
|
||||||
@@ -106,7 +107,7 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
|
|||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS)) && \
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 16,
|
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 16,
|
||||||
8, imgSFL1);
|
8, imgSFL1);
|
||||||
@@ -121,7 +122,8 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16
|
|||||||
} else {
|
} else {
|
||||||
// TODO: Raspberry Pi supports more than just the one screen size
|
// TODO: Raspberry Pi supports more than just the one screen size
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || ARCH_PORTDUINO) && \
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS) || \
|
||||||
|
ARCH_PORTDUINO) && \
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||||||
imgInfoL1);
|
imgInfoL1);
|
||||||
|
|||||||
@@ -434,8 +434,8 @@ void menuHandler::systemBaseMenu()
|
|||||||
|
|
||||||
optionsArray[options] = "Notifications";
|
optionsArray[options] = "Notifications";
|
||||||
optionsEnumArray[options++] = Notifications;
|
optionsEnumArray[options++] = Notifications;
|
||||||
#if defined(ST7789_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107) || \
|
#if defined(ST7789_CS) || defined(ST7796_CS) || defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || \
|
||||||
defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT
|
defined(USE_SH1107) || defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || HAS_TFT
|
||||||
optionsArray[options] = "Screen Options";
|
optionsArray[options] = "Screen Options";
|
||||||
optionsEnumArray[options++] = ScreenOptions;
|
optionsEnumArray[options++] = ScreenOptions;
|
||||||
#endif
|
#endif
|
||||||
@@ -725,7 +725,7 @@ void menuHandler::BrightnessPickerMenu()
|
|||||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190)
|
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190)
|
||||||
// For HELTEC devices, use analogWrite to control backlight
|
// For HELTEC devices, use analogWrite to control backlight
|
||||||
analogWrite(VTFT_LEDA, uiconfig.screen_brightness);
|
analogWrite(VTFT_LEDA, uiconfig.screen_brightness);
|
||||||
#elif defined(ST7789_CS)
|
#elif defined(ST7789_CS) || defined(ST7796_CS)
|
||||||
static_cast<TFTDisplay *>(screen->getDisplayDevice())->setDisplayBrightness(uiconfig.screen_brightness);
|
static_cast<TFTDisplay *>(screen->getDisplayDevice())->setDisplayBrightness(uiconfig.screen_brightness);
|
||||||
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
#elif defined(USE_OLED) || defined(USE_SSD1306) || defined(USE_SH1106) || defined(USE_SH1107)
|
||||||
screen->getDisplayDevice()->setBrightness(uiconfig.screen_brightness);
|
screen->getDisplayDevice()->setBrightness(uiconfig.screen_brightness);
|
||||||
@@ -768,7 +768,7 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
|
|||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = 10;
|
bannerOptions.optionsCount = 10;
|
||||||
bannerOptions.bannerCallback = [display](int selected) -> void {
|
bannerOptions.bannerCallback = [display](int selected) -> void {
|
||||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || HAS_TFT
|
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || HAS_TFT
|
||||||
uint8_t TFT_MESH_r = 0;
|
uint8_t TFT_MESH_r = 0;
|
||||||
uint8_t TFT_MESH_g = 0;
|
uint8_t TFT_MESH_g = 0;
|
||||||
uint8_t TFT_MESH_b = 0;
|
uint8_t TFT_MESH_b = 0;
|
||||||
@@ -1045,7 +1045,7 @@ void menuHandler::screenOptionsMenu()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only show screen color for TFT displays
|
// Only show screen color for TFT displays
|
||||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || HAS_TFT
|
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || HAS_TFT
|
||||||
optionsArray[options] = "Screen Color";
|
optionsArray[options] = "Screen Color";
|
||||||
optionsEnumArray[options++] = ScreenColor;
|
optionsEnumArray[options++] = ScreenColor;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ void UIRenderer::drawNodes(OLEDDisplay *display, int16_t x, int16_t y, const mes
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || defined(ST7796_CS)) && \
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
|
|
||||||
if (isHighResolution) {
|
if (isHighResolution) {
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03
|
|||||||
0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f};
|
0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f};
|
||||||
|
|
||||||
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||||||
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || ARCH_PORTDUINO) && \
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS) || \
|
||||||
|
ARCH_PORTDUINO) && \
|
||||||
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||||||
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
const uint8_t imgQuestionL1[] PROGMEM = {0xff, 0x01, 0x01, 0x32, 0x7b, 0x49, 0x49, 0x6f, 0x26, 0x01, 0x01, 0xff};
|
||||||
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
const uint8_t imgQuestionL2[] PROGMEM = {0x0f, 0x08, 0x08, 0x08, 0x06, 0x0f, 0x0f, 0x06, 0x08, 0x08, 0x08, 0x0f};
|
||||||
|
|||||||
68
src/graphics/niche/Drivers/EInk/ZJY122250_0213BAAMFGN.cpp
Normal file
68
src/graphics/niche/Drivers/EInk/ZJY122250_0213BAAMFGN.cpp
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#include "./ZJY122250_0213BAAMFGN.h"
|
||||||
|
|
||||||
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||||
|
|
||||||
|
using namespace NicheGraphics::Drivers;
|
||||||
|
|
||||||
|
// Map the display controller IC's output to the connected panel
|
||||||
|
void ZJY122250_0213BAAMFGN::configScanning()
|
||||||
|
{
|
||||||
|
// "Driver output control"
|
||||||
|
// Scan gates from 0 to 249 (vertical resolution 250px)
|
||||||
|
sendCommand(0x01);
|
||||||
|
sendData(0xF9);
|
||||||
|
sendData(0x00);
|
||||||
|
sendData(0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 ZJY122250_0213BAAMFGN::configWaveform()
|
||||||
|
{
|
||||||
|
switch (updateType) {
|
||||||
|
case FAST:
|
||||||
|
sendCommand(0x3C); // Border waveform:
|
||||||
|
sendData(0x80); // VCOM
|
||||||
|
break;
|
||||||
|
case FULL:
|
||||||
|
default:
|
||||||
|
sendCommand(0x3C); // Border waveform:
|
||||||
|
sendData(0x01); // Follow LUT 1 (blink same as white pixels)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCommand(0x18); // Temperature sensor:
|
||||||
|
sendData(0x80); // Use internal temperature sensor to select an appropriate refresh waveform
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZJY122250_0213BAAMFGN::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 ZJY122250_0213BAAMFGN::detachFromUpdate()
|
||||||
|
{
|
||||||
|
switch (updateType) {
|
||||||
|
case FAST:
|
||||||
|
return beginPolling(50, 500); // At least 500ms for fast refresh
|
||||||
|
case FULL:
|
||||||
|
default:
|
||||||
|
return beginPolling(100, 2000); // At least 2 seconds for full refresh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||||
42
src/graphics/niche/Drivers/EInk/ZJY122250_0213BAAMFGN.h
Normal file
42
src/graphics/niche/Drivers/EInk/ZJY122250_0213BAAMFGN.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
E-Ink display driver
|
||||||
|
- ZJY122250_0213BAAMFGN
|
||||||
|
- Manufacturer: Zhongjingyuan
|
||||||
|
- Size: 2.13 inch
|
||||||
|
- Resolution: 250px x 122px
|
||||||
|
- Flex connector marking (not a unique identifier): FPC-A002
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#include "./SSD16XX.h"
|
||||||
|
|
||||||
|
namespace NicheGraphics::Drivers
|
||||||
|
{
|
||||||
|
class ZJY122250_0213BAAMFGN : 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:
|
||||||
|
ZJY122250_0213BAAMFGN() : SSD16XX(width, height, supported) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void configScanning() override;
|
||||||
|
virtual void configWaveform() override;
|
||||||
|
virtual void configUpdateSequence() override;
|
||||||
|
void detachFromUpdate() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace NicheGraphics::Drivers
|
||||||
|
|
||||||
|
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||||
@@ -7,12 +7,7 @@ using namespace NicheGraphics;
|
|||||||
|
|
||||||
// Timing for "maintenance"
|
// Timing for "maintenance"
|
||||||
// Paying off full-refresh debt with unprovoked updates, if the display is not very active
|
// Paying off full-refresh debt with unprovoked updates, if the display is not very active
|
||||||
|
|
||||||
#ifdef SEEED_WIO_TRACKER_L1
|
|
||||||
static constexpr uint32_t MAINTENANCE_MS_INITIAL = 5 * 1000UL;
|
|
||||||
#else
|
|
||||||
static constexpr uint32_t MAINTENANCE_MS_INITIAL = 60 * 1000UL;
|
static constexpr uint32_t MAINTENANCE_MS_INITIAL = 60 * 1000UL;
|
||||||
#endif
|
|
||||||
static constexpr uint32_t MAINTENANCE_MS = 60 * 60 * 1000UL;
|
static constexpr uint32_t MAINTENANCE_MS = 60 * 60 * 1000UL;
|
||||||
|
|
||||||
InkHUD::DisplayHealth::DisplayHealth() : concurrency::OSThread("Mediator")
|
InkHUD::DisplayHealth::DisplayHealth() : concurrency::OSThread("Mediator")
|
||||||
|
|||||||
76
src/input/RotaryEncoderImpl.cpp
Normal file
76
src/input/RotaryEncoderImpl.cpp
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#ifdef T_LORA_PAGER
|
||||||
|
|
||||||
|
#include "RotaryEncoderImpl.h"
|
||||||
|
#include "InputBroker.h"
|
||||||
|
#include "RotaryEncoder.h"
|
||||||
|
|
||||||
|
#define ORIGIN_NAME "RotaryEncoder"
|
||||||
|
|
||||||
|
RotaryEncoderImpl *rotaryEncoderImpl;
|
||||||
|
|
||||||
|
RotaryEncoderImpl::RotaryEncoderImpl() : concurrency::OSThread(ORIGIN_NAME), originName(ORIGIN_NAME)
|
||||||
|
{
|
||||||
|
rotary = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RotaryEncoderImpl::init()
|
||||||
|
{
|
||||||
|
if (!moduleConfig.canned_message.updown1_enabled || moduleConfig.canned_message.inputbroker_pin_a == 0 ||
|
||||||
|
moduleConfig.canned_message.inputbroker_pin_b == 0) {
|
||||||
|
// Input device is disabled.
|
||||||
|
disable();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
eventCw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_cw);
|
||||||
|
eventCcw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_ccw);
|
||||||
|
eventPressed = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_press);
|
||||||
|
|
||||||
|
rotary = new RotaryEncoder(moduleConfig.canned_message.inputbroker_pin_a, moduleConfig.canned_message.inputbroker_pin_b,
|
||||||
|
moduleConfig.canned_message.inputbroker_pin_press);
|
||||||
|
rotary->resetButton();
|
||||||
|
|
||||||
|
inputBroker->registerSource(this);
|
||||||
|
|
||||||
|
LOG_INFO("RotaryEncoder initialized pins(%d, %d, %d), events(%d, %d, %d)", moduleConfig.canned_message.inputbroker_pin_a,
|
||||||
|
moduleConfig.canned_message.inputbroker_pin_b, moduleConfig.canned_message.inputbroker_pin_press, eventCw, eventCcw,
|
||||||
|
eventPressed);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t RotaryEncoderImpl::runOnce()
|
||||||
|
{
|
||||||
|
InputEvent e;
|
||||||
|
e.inputEvent = INPUT_BROKER_NONE;
|
||||||
|
e.source = this->originName;
|
||||||
|
|
||||||
|
static uint32_t lastPressed = millis();
|
||||||
|
if (rotary->readButton() == RotaryEncoder::ButtonState::BUTTON_PRESSED) {
|
||||||
|
if (lastPressed + 200 < millis()) {
|
||||||
|
LOG_DEBUG("Rotary event Press");
|
||||||
|
lastPressed = millis();
|
||||||
|
e.inputEvent = this->eventPressed;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (rotary->process()) {
|
||||||
|
case RotaryEncoder::DIRECTION_CW:
|
||||||
|
LOG_DEBUG("Rotary event CW");
|
||||||
|
e.inputEvent = this->eventCw;
|
||||||
|
break;
|
||||||
|
case RotaryEncoder::DIRECTION_CCW:
|
||||||
|
LOG_DEBUG("Rotary event CCW");
|
||||||
|
e.inputEvent = this->eventCcw;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.inputEvent != INPUT_BROKER_NONE) {
|
||||||
|
this->notifyObservers(&e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
28
src/input/RotaryEncoderImpl.h
Normal file
28
src/input/RotaryEncoderImpl.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// This is a non-interrupt version of RotaryEncoder which is based on a debounce inherent FSM table (see RotaryEncoder library)
|
||||||
|
|
||||||
|
#include "InputBroker.h"
|
||||||
|
#include "concurrency/OSThread.h"
|
||||||
|
#include "mesh/NodeDB.h"
|
||||||
|
|
||||||
|
class RotaryEncoder;
|
||||||
|
|
||||||
|
class RotaryEncoderImpl : public Observable<const InputEvent *>, public concurrency::OSThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RotaryEncoderImpl();
|
||||||
|
bool init(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int32_t runOnce() override;
|
||||||
|
|
||||||
|
input_broker_event eventCw = INPUT_BROKER_NONE;
|
||||||
|
input_broker_event eventCcw = INPUT_BROKER_NONE;
|
||||||
|
input_broker_event eventPressed = INPUT_BROKER_NONE;
|
||||||
|
|
||||||
|
RotaryEncoder *rotary;
|
||||||
|
const char *originName;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern RotaryEncoderImpl *rotaryEncoderImpl;
|
||||||
@@ -18,14 +18,23 @@ void RotaryEncoderInterruptBase::init(
|
|||||||
this->_eventCcw = eventCcw;
|
this->_eventCcw = eventCcw;
|
||||||
this->_eventPressed = eventPressed;
|
this->_eventPressed = eventPressed;
|
||||||
|
|
||||||
pinMode(pinPress, INPUT_PULLUP);
|
bool isRAK = false;
|
||||||
pinMode(this->_pinA, INPUT_PULLUP);
|
#ifdef RAK_4631
|
||||||
pinMode(this->_pinB, INPUT_PULLUP);
|
isRAK = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
// attachInterrupt(pinPress, onIntPress, RISING);
|
if (!isRAK || pinPress != 0) {
|
||||||
attachInterrupt(pinPress, onIntPress, RISING);
|
pinMode(pinPress, INPUT_PULLUP);
|
||||||
attachInterrupt(this->_pinA, onIntA, CHANGE);
|
attachInterrupt(pinPress, onIntPress, RISING);
|
||||||
attachInterrupt(this->_pinB, onIntB, CHANGE);
|
}
|
||||||
|
if (!isRAK || this->_pinA != 0) {
|
||||||
|
pinMode(this->_pinA, INPUT_PULLUP);
|
||||||
|
attachInterrupt(this->_pinA, onIntA, CHANGE);
|
||||||
|
}
|
||||||
|
if (!isRAK || this->_pinA != 0) {
|
||||||
|
pinMode(this->_pinB, INPUT_PULLUP);
|
||||||
|
attachInterrupt(this->_pinB, onIntB, CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
this->rotaryLevelA = digitalRead(this->_pinA);
|
this->rotaryLevelA = digitalRead(this->_pinA);
|
||||||
this->rotaryLevelB = digitalRead(this->_pinB);
|
this->rotaryLevelB = digitalRead(this->_pinB);
|
||||||
|
|||||||
230
src/input/TLoraPagerKeyboard.cpp
Normal file
230
src/input/TLoraPagerKeyboard.cpp
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
#if defined(T_LORA_PAGER)
|
||||||
|
|
||||||
|
#include "TLoraPagerKeyboard.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
#ifndef LEDC_BACKLIGHT_CHANNEL
|
||||||
|
#define LEDC_BACKLIGHT_CHANNEL 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LEDC_BACKLIGHT_BIT_WIDTH
|
||||||
|
#define LEDC_BACKLIGHT_BIT_WIDTH 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LEDC_BACKLIGHT_FREQ
|
||||||
|
#define LEDC_BACKLIGHT_FREQ 1000 // Hz
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _TCA8418_COLS 10
|
||||||
|
#define _TCA8418_ROWS 4
|
||||||
|
#define _TCA8418_NUM_KEYS 31
|
||||||
|
|
||||||
|
#define _TCA8418_MULTI_TAP_THRESHOLD 1500
|
||||||
|
|
||||||
|
using Key = TCA8418KeyboardBase::TCA8418Key;
|
||||||
|
|
||||||
|
constexpr uint8_t modifierRightShiftKey = 29 - 1; // keynum -1
|
||||||
|
constexpr uint8_t modifierRightShift = 0b0001;
|
||||||
|
constexpr uint8_t modifierSymKey = 21 - 1;
|
||||||
|
constexpr uint8_t modifierSym = 0b0010;
|
||||||
|
|
||||||
|
// Num chars per key, Modulus for rotating through characters
|
||||||
|
static uint8_t TLoraPagerTapMod[_TCA8418_NUM_KEYS] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||||
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
|
||||||
|
|
||||||
|
static unsigned char TLoraPagerTapMap[_TCA8418_NUM_KEYS][3] = {{'q', 'Q', '1'},
|
||||||
|
{'w', 'W', '2'},
|
||||||
|
{'e', 'E', '3'},
|
||||||
|
{'r', 'R', '4'},
|
||||||
|
{'t', 'T', '5'},
|
||||||
|
{'y', 'Y', '6'},
|
||||||
|
{'u', 'U', '7'},
|
||||||
|
{'i', 'I', '8'},
|
||||||
|
{'o', 'O', '9'},
|
||||||
|
{'p', 'P', '0'},
|
||||||
|
{'a', 'A', '*'},
|
||||||
|
{'s', 'S', '/'},
|
||||||
|
{'d', 'D', '+'},
|
||||||
|
{'f', 'F', '-'},
|
||||||
|
{'g', 'G', '='},
|
||||||
|
{'h', 'H', ':'},
|
||||||
|
{'j', 'J', '\''},
|
||||||
|
{'k', 'K', '"'},
|
||||||
|
{'l', 'L', '@'},
|
||||||
|
{Key::SELECT, 0x00, Key::TAB},
|
||||||
|
{0x00, 0x00, 0x00},
|
||||||
|
{'z', 'Z', '_'},
|
||||||
|
{'x', 'X', '$'},
|
||||||
|
{'c', 'C', ';'},
|
||||||
|
{'v', 'V', '?'},
|
||||||
|
{'b', 'B', '!'},
|
||||||
|
{'n', 'N', ','},
|
||||||
|
{'m', 'M', '.'},
|
||||||
|
{0x00, 0x00, 0x00},
|
||||||
|
{Key::BSP, 0x00, Key::ESC},
|
||||||
|
{' ', 0x00, Key::BL_TOGGLE}};
|
||||||
|
|
||||||
|
TLoraPagerKeyboard::TLoraPagerKeyboard()
|
||||||
|
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), modifierFlag(0), last_modifier_time(0), last_key(-1), next_key(-1),
|
||||||
|
last_tap(0L), char_idx(0), tap_interval(0)
|
||||||
|
{
|
||||||
|
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||||
|
ledcAttach(KB_BL_PIN, LEDC_BACKLIGHT_FREQ, LEDC_BACKLIGHT_BIT_WIDTH);
|
||||||
|
#else
|
||||||
|
ledcSetup(LEDC_BACKLIGHT_CHANNEL, LEDC_BACKLIGHT_FREQ, LEDC_BACKLIGHT_BIT_WIDTH);
|
||||||
|
ledcAttachPin(KB_BL_PIN, LEDC_BACKLIGHT_CHANNEL);
|
||||||
|
#endif
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TLoraPagerKeyboard::reset(void)
|
||||||
|
{
|
||||||
|
TCA8418KeyboardBase::reset();
|
||||||
|
pinMode(KB_BL_PIN, OUTPUT);
|
||||||
|
digitalWrite(KB_BL_PIN, LOW);
|
||||||
|
setBacklight(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle multi-key presses (shift and alt)
|
||||||
|
void TLoraPagerKeyboard::trigger()
|
||||||
|
{
|
||||||
|
uint8_t count = keyCount();
|
||||||
|
if (count == 0)
|
||||||
|
return;
|
||||||
|
for (uint8_t i = 0; i < count; ++i) {
|
||||||
|
uint8_t k = readRegister(TCA8418_REG_KEY_EVENT_A + i);
|
||||||
|
uint8_t key = k & 0x7F;
|
||||||
|
if (k & 0x80) {
|
||||||
|
pressed(key);
|
||||||
|
} else {
|
||||||
|
released();
|
||||||
|
state = Idle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TLoraPagerKeyboard::setBacklight(bool on)
|
||||||
|
{
|
||||||
|
toggleBacklight(!on);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TLoraPagerKeyboard::pressed(uint8_t key)
|
||||||
|
{
|
||||||
|
if (state == Init || state == Busy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_ALL_ENABLED ||
|
||||||
|
config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_SYSTEM_ONLY) {
|
||||||
|
hapticFeedback();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modifierFlag && (millis() - last_modifier_time > _TCA8418_MULTI_TAP_THRESHOLD)) {
|
||||||
|
modifierFlag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t next_key = 0;
|
||||||
|
int row = (key - 1) / 10;
|
||||||
|
int col = (key - 1) % 10;
|
||||||
|
|
||||||
|
if (row >= _TCA8418_ROWS || col >= _TCA8418_COLS) {
|
||||||
|
return; // Invalid key
|
||||||
|
}
|
||||||
|
|
||||||
|
next_key = row * _TCA8418_COLS + col;
|
||||||
|
state = Held;
|
||||||
|
|
||||||
|
uint32_t now = millis();
|
||||||
|
tap_interval = now - last_tap;
|
||||||
|
|
||||||
|
updateModifierFlag(next_key);
|
||||||
|
if (isModifierKey(next_key)) {
|
||||||
|
last_modifier_time = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tap_interval < 0) {
|
||||||
|
last_tap = 0;
|
||||||
|
state = Busy;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_key != last_key || tap_interval > _TCA8418_MULTI_TAP_THRESHOLD) {
|
||||||
|
char_idx = 0;
|
||||||
|
} else {
|
||||||
|
char_idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_key = next_key;
|
||||||
|
last_tap = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TLoraPagerKeyboard::released()
|
||||||
|
{
|
||||||
|
if (state != Held) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_key < 0 || last_key >= _TCA8418_NUM_KEYS) {
|
||||||
|
last_key = -1;
|
||||||
|
state = Idle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t now = millis();
|
||||||
|
last_tap = now;
|
||||||
|
|
||||||
|
if (TLoraPagerTapMap[last_key][modifierFlag % TLoraPagerTapMod[last_key]] == Key::BL_TOGGLE) {
|
||||||
|
toggleBacklight();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
queueEvent(TLoraPagerTapMap[last_key][modifierFlag % TLoraPagerTapMod[last_key]]);
|
||||||
|
if (isModifierKey(last_key) == false)
|
||||||
|
modifierFlag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TLoraPagerKeyboard::hapticFeedback()
|
||||||
|
{
|
||||||
|
drv.setWaveform(0, 14); // strong buzz 100%
|
||||||
|
drv.setWaveform(1, 0); // end waveform
|
||||||
|
drv.go();
|
||||||
|
}
|
||||||
|
|
||||||
|
// toggle brightness of the backlight in three steps
|
||||||
|
void TLoraPagerKeyboard::toggleBacklight(bool off)
|
||||||
|
{
|
||||||
|
static uint32_t brightness = 0;
|
||||||
|
if (off) {
|
||||||
|
brightness = 0;
|
||||||
|
} else {
|
||||||
|
if (brightness == 0) {
|
||||||
|
brightness = 40;
|
||||||
|
} else if (brightness == 40) {
|
||||||
|
brightness = 127;
|
||||||
|
} else if (brightness >= 127) {
|
||||||
|
brightness = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG_DEBUG("Toggle backlight: %d", brightness);
|
||||||
|
|
||||||
|
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
|
||||||
|
ledcWrite(KB_BL_PIN, brightness);
|
||||||
|
#else
|
||||||
|
ledcWrite(LEDC_BACKLIGHT_CHANNEL, brightness);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void TLoraPagerKeyboard::updateModifierFlag(uint8_t key)
|
||||||
|
{
|
||||||
|
if (key == modifierRightShiftKey) {
|
||||||
|
modifierFlag ^= modifierRightShift;
|
||||||
|
} else if (key == modifierSymKey) {
|
||||||
|
modifierFlag ^= modifierSym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TLoraPagerKeyboard::isModifierKey(uint8_t key)
|
||||||
|
{
|
||||||
|
return (key == modifierRightShiftKey || key == modifierSymKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -4,9 +4,26 @@ class TLoraPagerKeyboard : public TCA8418KeyboardBase
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TLoraPagerKeyboard();
|
TLoraPagerKeyboard();
|
||||||
void setBacklight(bool on) override{};
|
void reset(void);
|
||||||
|
void trigger(void) override;
|
||||||
|
void setBacklight(bool on) override;
|
||||||
|
virtual ~TLoraPagerKeyboard() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void pressed(uint8_t key) override{};
|
void pressed(uint8_t key) override;
|
||||||
void released(void) override{};
|
void released(void) override;
|
||||||
|
void hapticFeedback(void);
|
||||||
|
|
||||||
|
void updateModifierFlag(uint8_t key);
|
||||||
|
bool isModifierKey(uint8_t key);
|
||||||
|
void toggleBacklight(bool off = false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t modifierFlag; // Flag to indicate if a modifier key is pressed
|
||||||
|
uint32_t last_modifier_time; // Timestamp of the last modifier key press
|
||||||
|
int8_t last_key;
|
||||||
|
int8_t next_key;
|
||||||
|
uint32_t last_tap;
|
||||||
|
uint8_t char_idx;
|
||||||
|
int32_t tap_interval;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,14 +15,23 @@ void UpDownInterruptBase::init(uint8_t pinDown, uint8_t pinUp, uint8_t pinPress,
|
|||||||
this->_eventDown = eventDown;
|
this->_eventDown = eventDown;
|
||||||
this->_eventUp = eventUp;
|
this->_eventUp = eventUp;
|
||||||
this->_eventPressed = eventPressed;
|
this->_eventPressed = eventPressed;
|
||||||
|
bool isRAK = false;
|
||||||
|
#ifdef RAK_4631
|
||||||
|
isRAK = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
pinMode(pinPress, INPUT_PULLUP);
|
if (!isRAK || pinPress != 0) {
|
||||||
pinMode(this->_pinDown, INPUT_PULLUP);
|
pinMode(pinPress, INPUT_PULLUP);
|
||||||
pinMode(this->_pinUp, INPUT_PULLUP);
|
attachInterrupt(pinPress, onIntPress, RISING);
|
||||||
|
}
|
||||||
attachInterrupt(pinPress, onIntPress, RISING);
|
if (!isRAK || this->_pinDown != 0) {
|
||||||
attachInterrupt(this->_pinDown, onIntDown, RISING);
|
pinMode(this->_pinDown, INPUT_PULLUP);
|
||||||
attachInterrupt(this->_pinUp, onIntUp, RISING);
|
attachInterrupt(this->_pinDown, onIntDown, RISING);
|
||||||
|
}
|
||||||
|
if (!isRAK || this->_pinUp != 0) {
|
||||||
|
pinMode(this->_pinUp, INPUT_PULLUP);
|
||||||
|
attachInterrupt(this->_pinUp, onIntUp, RISING);
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG("Up/down/press GPIO initialized (%d, %d, %d)", this->_pinUp, this->_pinDown, pinPress);
|
LOG_DEBUG("Up/down/press GPIO initialized (%d, %d, %d)", this->_pinUp, this->_pinDown, pinPress);
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ void CardKbI2cImpl::init()
|
|||||||
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(I2C_NO_RESCAN)
|
#if !MESHTASTIC_EXCLUDE_I2C && !defined(ARCH_PORTDUINO) && !defined(I2C_NO_RESCAN)
|
||||||
if (cardkb_found.address == 0x00) {
|
if (cardkb_found.address == 0x00) {
|
||||||
LOG_DEBUG("Rescan for I2C keyboard");
|
LOG_DEBUG("Rescan for I2C keyboard");
|
||||||
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR, XPOWERS_AXP192_AXP2101_ADDRESS};
|
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR, TCA8418_KB_ADDR};
|
||||||
uint8_t i2caddr_asize = 5;
|
uint8_t i2caddr_asize = sizeof(i2caddr_scan) / sizeof(i2caddr_scan[0]);
|
||||||
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
||||||
|
|
||||||
#if WIRE_INTERFACES_COUNT == 2
|
#if WIRE_INTERFACES_COUNT == 2
|
||||||
|
|||||||
55
src/main.cpp
55
src/main.cpp
@@ -135,8 +135,9 @@ AccelerometerThread *accelerometerThread = nullptr;
|
|||||||
AudioThread *audioThread = nullptr;
|
AudioThread *audioThread = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_PCA9557
|
#ifdef USE_XL9555
|
||||||
PCA9557 IOEXP;
|
#include "ExtensionIOXL9555.hpp"
|
||||||
|
ExtensionIOXL9555 io;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HAS_TFT
|
#if HAS_TFT
|
||||||
@@ -201,7 +202,7 @@ ScanI2C::FoundDevice rgb_found = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE,
|
|||||||
/// The I2C address of our Air Quality Indicator (if found)
|
/// The I2C address of our Air Quality Indicator (if found)
|
||||||
ScanI2C::DeviceAddress aqi_found = ScanI2C::ADDRESS_NONE;
|
ScanI2C::DeviceAddress aqi_found = ScanI2C::ADDRESS_NONE;
|
||||||
|
|
||||||
#ifdef T_WATCH_S3
|
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
||||||
Adafruit_DRV2605 drv;
|
Adafruit_DRV2605 drv;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -359,6 +360,30 @@ void setup()
|
|||||||
digitalWrite(SDCARD_CS, HIGH);
|
digitalWrite(SDCARD_CS, HIGH);
|
||||||
pinMode(PIN_EINK_CS, OUTPUT);
|
pinMode(PIN_EINK_CS, OUTPUT);
|
||||||
digitalWrite(PIN_EINK_CS, HIGH);
|
digitalWrite(PIN_EINK_CS, HIGH);
|
||||||
|
#elif defined(T_LORA_PAGER)
|
||||||
|
pinMode(LORA_CS, OUTPUT);
|
||||||
|
digitalWrite(LORA_CS, HIGH);
|
||||||
|
pinMode(SDCARD_CS, OUTPUT);
|
||||||
|
digitalWrite(SDCARD_CS, HIGH);
|
||||||
|
pinMode(TFT_CS, OUTPUT);
|
||||||
|
digitalWrite(TFT_CS, HIGH);
|
||||||
|
// io expander
|
||||||
|
io.begin(Wire, XL9555_SLAVE_ADDRESS0, SDA, SCL);
|
||||||
|
io.pinMode(EXPANDS_DRV_EN, OUTPUT);
|
||||||
|
io.digitalWrite(EXPANDS_DRV_EN, HIGH);
|
||||||
|
io.pinMode(EXPANDS_AMP_EN, OUTPUT);
|
||||||
|
io.digitalWrite(EXPANDS_AMP_EN, HIGH);
|
||||||
|
io.pinMode(EXPANDS_LORA_EN, OUTPUT);
|
||||||
|
io.digitalWrite(EXPANDS_LORA_EN, HIGH);
|
||||||
|
io.pinMode(EXPANDS_GPS_EN, OUTPUT);
|
||||||
|
io.digitalWrite(EXPANDS_GPS_EN, HIGH);
|
||||||
|
io.pinMode(EXPANDS_KB_EN, OUTPUT);
|
||||||
|
io.digitalWrite(EXPANDS_KB_EN, HIGH);
|
||||||
|
io.pinMode(EXPANDS_SD_EN, OUTPUT);
|
||||||
|
io.digitalWrite(EXPANDS_SD_EN, HIGH);
|
||||||
|
io.pinMode(EXPANDS_GPIO_EN, OUTPUT);
|
||||||
|
io.digitalWrite(EXPANDS_GPIO_EN, HIGH);
|
||||||
|
io.pinMode(EXPANDS_SD_PULLEN, INPUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
concurrency::hasBeenSetup = true;
|
concurrency::hasBeenSetup = true;
|
||||||
@@ -404,6 +429,16 @@ void setup()
|
|||||||
|
|
||||||
initDeepSleep();
|
initDeepSleep();
|
||||||
|
|
||||||
|
#if defined(MODEM_POWER_EN)
|
||||||
|
pinMode(MODEM_POWER_EN, OUTPUT);
|
||||||
|
digitalWrite(MODEM_POWER_EN, LOW);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MODEM_PWRKEY)
|
||||||
|
pinMode(MODEM_PWRKEY, OUTPUT);
|
||||||
|
digitalWrite(MODEM_PWRKEY, LOW);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(LORA_TCXO_GPIO)
|
#if defined(LORA_TCXO_GPIO)
|
||||||
pinMode(LORA_TCXO_GPIO, OUTPUT);
|
pinMode(LORA_TCXO_GPIO, OUTPUT);
|
||||||
digitalWrite(LORA_TCXO_GPIO, HIGH);
|
digitalWrite(LORA_TCXO_GPIO, HIGH);
|
||||||
@@ -795,7 +830,7 @@ void setup()
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef T_WATCH_S3
|
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
||||||
drv.begin();
|
drv.begin();
|
||||||
drv.selectLibrary(1);
|
drv.selectLibrary(1);
|
||||||
// I2C trigger by sending 'go' command
|
// I2C trigger by sending 'go' command
|
||||||
@@ -841,7 +876,7 @@ void setup()
|
|||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||||
|
|
||||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
||||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS)
|
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||||
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
|
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
|
||||||
#elif defined(ARCH_PORTDUINO)
|
#elif defined(ARCH_PORTDUINO)
|
||||||
if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) &&
|
if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) &&
|
||||||
@@ -1104,7 +1139,7 @@ void setup()
|
|||||||
// Don't call screen setup until after nodedb is setup (because we need
|
// Don't call screen setup until after nodedb is setup (because we need
|
||||||
// the current region name)
|
// the current region name)
|
||||||
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
#if defined(ST7701_CS) || defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || \
|
||||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS)
|
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||||
if (screen)
|
if (screen)
|
||||||
screen->setup();
|
screen->setup();
|
||||||
#elif defined(ARCH_PORTDUINO)
|
#elif defined(ARCH_PORTDUINO)
|
||||||
@@ -1562,7 +1597,13 @@ void loop()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
service->loop();
|
service->loop();
|
||||||
|
#if defined(LGFX_SDL)
|
||||||
|
if (screen) {
|
||||||
|
auto dispdev = screen->getDisplayDevice();
|
||||||
|
if (dispdev)
|
||||||
|
static_cast<TFTDisplay *>(dispdev)->sdlLoop();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
long delayMsec = mainController.runOrDelay();
|
long delayMsec = mainController.runOrDelay();
|
||||||
|
|
||||||
// We want to sleep as long as possible here - because it saves power
|
// We want to sleep as long as possible here - because it saves power
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ extern bool eink_found;
|
|||||||
extern bool pmu_found;
|
extern bool pmu_found;
|
||||||
extern bool isUSBPowered;
|
extern bool isUSBPowered;
|
||||||
|
|
||||||
#ifdef T_WATCH_S3
|
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
|
||||||
#include <Adafruit_DRV2605.h>
|
#include <Adafruit_DRV2605.h>
|
||||||
extern Adafruit_DRV2605 drv;
|
extern Adafruit_DRV2605 drv;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
#include "mesh/NodeDB.h"
|
#include "mesh/NodeDB.h"
|
||||||
#ifdef LR11X0_DIO_AS_RF_SWITCH
|
#ifdef LR11X0_DIO_AS_RF_SWITCH
|
||||||
#include "rfswitch.h"
|
#include "rfswitch.h"
|
||||||
|
#elif ARCH_PORTDUINO
|
||||||
|
#include "PortduinoGlue.h"
|
||||||
|
#define rfswitch_dio_pins portduino_config.rfswitch_dio_pins
|
||||||
|
#define rfswitch_table portduino_config.rfswitch_table
|
||||||
#else
|
#else
|
||||||
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
|
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
|
||||||
static const Module::RfSwitchMode_t rfswitch_table[] = {
|
static const Module::RfSwitchMode_t rfswitch_table[] = {
|
||||||
@@ -14,10 +18,6 @@ static const Module::RfSwitchMode_t rfswitch_table[] = {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARCH_PORTDUINO
|
|
||||||
#include "PortduinoGlue.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Particular boards might define a different max power based on what their hardware can do, default to max power output if not
|
// Particular boards might define a different max power based on what their hardware can do, default to max power output if not
|
||||||
// specified (may be dangerous if using external PA and LR11x0 power config forgotten)
|
// specified (may be dangerous if using external PA and LR11x0 power config forgotten)
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
@@ -117,17 +117,14 @@ template <typename T> bool LR11x0Interface<T>::init()
|
|||||||
#ifdef LR11X0_DIO_AS_RF_SWITCH
|
#ifdef LR11X0_DIO_AS_RF_SWITCH
|
||||||
bool dioAsRfSwitch = true;
|
bool dioAsRfSwitch = true;
|
||||||
#elif defined(ARCH_PORTDUINO)
|
#elif defined(ARCH_PORTDUINO)
|
||||||
bool dioAsRfSwitch = false;
|
bool dioAsRfSwitch = portduino_config.has_rfswitch_table;
|
||||||
if (settingsMap[dio2_as_rf_switch]) {
|
|
||||||
dioAsRfSwitch = true;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
bool dioAsRfSwitch = false;
|
bool dioAsRfSwitch = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (dioAsRfSwitch) {
|
if (dioAsRfSwitch) {
|
||||||
lora.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table);
|
lora.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table);
|
||||||
LOG_DEBUG("Set DIO RF switch", res);
|
LOG_DEBUG("Set DIO RF switch");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res == RADIOLIB_ERR_NONE) {
|
if (res == RADIOLIB_ERR_NONE) {
|
||||||
|
|||||||
@@ -225,7 +225,11 @@ NodeDB::NodeDB()
|
|||||||
memcpy(myNodeInfo.device_id.bytes + sizeof(device_id_start), &device_id_end, sizeof(device_id_end));
|
memcpy(myNodeInfo.device_id.bytes + sizeof(device_id_start), &device_id_end, sizeof(device_id_end));
|
||||||
myNodeInfo.device_id.size = 16;
|
myNodeInfo.device_id.size = 16;
|
||||||
// Uncomment below to print the device id
|
// Uncomment below to print the device id
|
||||||
|
#elif ARCH_PORTDUINO
|
||||||
|
if (portduino_config.has_device_id) {
|
||||||
|
memcpy(myNodeInfo.device_id.bytes, portduino_config.device_id, 16);
|
||||||
|
myNodeInfo.device_id.size = 16;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
// FIXME - implement for other platforms
|
// FIXME - implement for other platforms
|
||||||
#endif
|
#endif
|
||||||
@@ -659,7 +663,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
|||||||
config.bluetooth.fixed_pin = defaultBLEPin;
|
config.bluetooth.fixed_pin = defaultBLEPin;
|
||||||
|
|
||||||
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
|
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7789_CS) || \
|
||||||
defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS)
|
defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||||
bool hasScreen = true;
|
bool hasScreen = true;
|
||||||
#ifdef HELTEC_MESH_NODE_T114
|
#ifdef HELTEC_MESH_NODE_T114
|
||||||
uint32_t st7789_id = get_st7789_id(ST7789_NSS, ST7789_SCK, ST7789_SDA, ST7789_RS, ST7789_RESET);
|
uint32_t st7789_id = get_st7789_id(ST7789_NSS, ST7789_SCK, ST7789_SDA, ST7789_RS, ST7789_RESET);
|
||||||
@@ -826,6 +830,15 @@ void NodeDB::installDefaultModuleConfig()
|
|||||||
moduleConfig.external_notification.alert_message = true;
|
moduleConfig.external_notification.alert_message = true;
|
||||||
moduleConfig.external_notification.output_ms = 1000;
|
moduleConfig.external_notification.output_ms = 1000;
|
||||||
moduleConfig.external_notification.nag_timeout = 60;
|
moduleConfig.external_notification.nag_timeout = 60;
|
||||||
|
#endif
|
||||||
|
#ifdef T_LORA_PAGER
|
||||||
|
moduleConfig.canned_message.updown1_enabled = true;
|
||||||
|
moduleConfig.canned_message.inputbroker_pin_a = ROTARY_A;
|
||||||
|
moduleConfig.canned_message.inputbroker_pin_b = ROTARY_B;
|
||||||
|
moduleConfig.canned_message.inputbroker_pin_press = ROTARY_PRESS;
|
||||||
|
moduleConfig.canned_message.inputbroker_event_cw = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar(28);
|
||||||
|
moduleConfig.canned_message.inputbroker_event_ccw = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar(29);
|
||||||
|
moduleConfig.canned_message.inputbroker_event_press = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||||
#endif
|
#endif
|
||||||
moduleConfig.has_canned_message = true;
|
moduleConfig.has_canned_message = true;
|
||||||
#if USERPREFS_MQTT_ENABLED && !MESHTASTIC_EXCLUDE_MQTT
|
#if USERPREFS_MQTT_ENABLED && !MESHTASTIC_EXCLUDE_MQTT
|
||||||
|
|||||||
@@ -192,12 +192,6 @@ 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()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// In case we send a FromRadio packet
|
|
||||||
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
|
|
||||||
|
|
||||||
// Respond to heartbeat by sending queue status
|
// Respond to heartbeat by sending queue status
|
||||||
if (heartbeatReceived) {
|
if (heartbeatReceived) {
|
||||||
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
|
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
|
||||||
@@ -209,6 +203,12 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
|||||||
return numbytes;
|
return numbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!available()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// In case we send a FromRadio packet
|
||||||
|
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
|
||||||
|
|
||||||
// Advance states as needed
|
// Advance states as needed
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case STATE_SEND_NOTHING:
|
case STATE_SEND_NOTHING:
|
||||||
|
|||||||
@@ -523,12 +523,15 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
|
|||||||
// is not in the local nodedb
|
// is not in the local nodedb
|
||||||
// First, only PKC encrypt packets we are originating
|
// First, only PKC encrypt packets we are originating
|
||||||
if (isFromUs(p) &&
|
if (isFromUs(p) &&
|
||||||
// Don't use PKC with simulator
|
#if ARCH_PORTDUINO
|
||||||
radioType != SIM_RADIO &&
|
// Sim radio via the cli flag skips PKC
|
||||||
|
!portduino_config.force_simradio &&
|
||||||
|
#endif
|
||||||
// Don't use PKC with Ham mode
|
// Don't use PKC with Ham mode
|
||||||
!owner.is_licensed &&
|
!owner.is_licensed &&
|
||||||
// Don't use PKC if it's not explicitly requested and a non-primary channel is requested
|
// Don't use PKC on 'serial' or 'gpio' channels unless explicitly requested
|
||||||
!(p->pki_encrypted != true && p->channel > 0) &&
|
!(p->pki_encrypted != true && (strcasecmp(channels.getName(chIndex), Channels::serialChannel) == 0 ||
|
||||||
|
strcasecmp(channels.getName(chIndex), Channels::gpioChannel) == 0)) &&
|
||||||
// Check for valid keys and single node destination
|
// Check for valid keys and single node destination
|
||||||
config.security.private_key.size == 32 && !isBroadcast(p->to) && node != nullptr &&
|
config.security.private_key.size == 32 && !isBroadcast(p->to) && node != nullptr &&
|
||||||
// Check for a known public key for the destination
|
// Check for a known public key for the destination
|
||||||
|
|||||||
@@ -16,6 +16,95 @@ int32_t StreamAPI::runOncePart()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t StreamAPI::runOncePart(char *buf, uint16_t bufLen)
|
||||||
|
{
|
||||||
|
auto result = readStream(buf, bufLen);
|
||||||
|
writeStream();
|
||||||
|
checkConnectionTimeout();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read any rx chars from the link and call handleRecStream
|
||||||
|
*/
|
||||||
|
int32_t StreamAPI::readStream(char *buf, uint16_t bufLen)
|
||||||
|
{
|
||||||
|
if (bufLen < 1) {
|
||||||
|
// Nothing available this time, if the computer has talked to us recently, poll often, otherwise let CPU sleep a long time
|
||||||
|
bool recentRx = Throttle::isWithinTimespanMs(lastRxMsec, 2000);
|
||||||
|
return recentRx ? 5 : 250;
|
||||||
|
} else {
|
||||||
|
handleRecStream(buf, bufLen);
|
||||||
|
// we had bytes available this time, so assume we might have them next time also
|
||||||
|
lastRxMsec = millis();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* call getFromRadio() and deliver encapsulated packets to the Stream
|
||||||
|
*/
|
||||||
|
void StreamAPI::writeStream()
|
||||||
|
{
|
||||||
|
if (canWrite) {
|
||||||
|
uint32_t len;
|
||||||
|
do {
|
||||||
|
// Send every packet we can
|
||||||
|
len = getFromRadio(txBuf + HEADER_LEN);
|
||||||
|
emitTxBuffer(len);
|
||||||
|
} while (len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t StreamAPI::handleRecStream(char *buf, uint16_t bufLen)
|
||||||
|
{
|
||||||
|
uint16_t index = 0;
|
||||||
|
while (bufLen > index) { // Currently we never want to block
|
||||||
|
int cInt = buf[index++];
|
||||||
|
if (cInt < 0)
|
||||||
|
break; // We ran out of characters (even though available said otherwise) - this can happen on rf52 adafruit
|
||||||
|
// arduino
|
||||||
|
|
||||||
|
uint8_t c = (uint8_t)cInt;
|
||||||
|
|
||||||
|
// Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
|
||||||
|
size_t ptr = rxPtr;
|
||||||
|
|
||||||
|
rxPtr++; // assume we will probably advance the rxPtr
|
||||||
|
rxBuf[ptr] = c; // store all bytes (including framing)
|
||||||
|
|
||||||
|
// console->printf("rxPtr %d ptr=%d c=0x%x\n", rxPtr, ptr, c);
|
||||||
|
|
||||||
|
if (ptr == 0) { // looking for START1
|
||||||
|
if (c != START1)
|
||||||
|
rxPtr = 0; // failed to find framing
|
||||||
|
} else if (ptr == 1) { // looking for START2
|
||||||
|
if (c != START2)
|
||||||
|
rxPtr = 0; // failed to find framing
|
||||||
|
} else if (ptr >= HEADER_LEN - 1) { // we have at least read our 4 byte framing
|
||||||
|
uint32_t len = (rxBuf[2] << 8) + rxBuf[3]; // big endian 16 bit length follows framing
|
||||||
|
|
||||||
|
// console->printf("len %d\n", len);
|
||||||
|
|
||||||
|
if (ptr == HEADER_LEN - 1) {
|
||||||
|
// we _just_ finished our 4 byte header, validate length now (note: a length of zero is a valid
|
||||||
|
// protobuf also)
|
||||||
|
if (len > MAX_TO_FROM_RADIO_SIZE)
|
||||||
|
rxPtr = 0; // length is bogus, restart search for framing
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rxPtr != 0) // Is packet still considered 'good'?
|
||||||
|
if (ptr + 1 >= len + HEADER_LEN) { // have we received all of the payload?
|
||||||
|
rxPtr = 0; // start over again on the next packet
|
||||||
|
|
||||||
|
// If we didn't just fail the packet and we now have the right # of bytes, parse it
|
||||||
|
handleToRadio(rxBuf + HEADER_LEN, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read any rx chars from the link and call handleToRadio
|
* Read any rx chars from the link and call handleToRadio
|
||||||
*/
|
*/
|
||||||
@@ -76,21 +165,6 @@ int32_t StreamAPI::readStream()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* call getFromRadio() and deliver encapsulated packets to the Stream
|
|
||||||
*/
|
|
||||||
void StreamAPI::writeStream()
|
|
||||||
{
|
|
||||||
if (canWrite) {
|
|
||||||
uint32_t len;
|
|
||||||
do {
|
|
||||||
// Send every packet we can
|
|
||||||
len = getFromRadio(txBuf + HEADER_LEN);
|
|
||||||
emitTxBuffer(len);
|
|
||||||
} while (len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send the current txBuffer over our stream
|
* Send the current txBuffer over our stream
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -50,12 +50,15 @@ class StreamAPI : public PhoneAPI
|
|||||||
* phone.
|
* phone.
|
||||||
*/
|
*/
|
||||||
virtual int32_t runOncePart();
|
virtual int32_t runOncePart();
|
||||||
|
virtual int32_t runOncePart(char *buf,uint16_t bufLen);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Read any rx chars from the link and call handleToRadio
|
* Read any rx chars from the link and call handleToRadio
|
||||||
*/
|
*/
|
||||||
int32_t readStream();
|
int32_t readStream();
|
||||||
|
int32_t readStream(char *buf,uint16_t bufLen);
|
||||||
|
int32_t handleRecStream(char *buf,uint16_t bufLen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* call getFromRadio() and deliver encapsulated packets to the Stream
|
* call getFromRadio() and deliver encapsulated packets to the Stream
|
||||||
|
|||||||
@@ -207,10 +207,10 @@ typedef enum _meshtastic_Config_DisplayConfig_OledType {
|
|||||||
meshtastic_Config_DisplayConfig_OledType_OLED_SSD1306 = 1,
|
meshtastic_Config_DisplayConfig_OledType_OLED_SSD1306 = 1,
|
||||||
/* Default / Autodetect */
|
/* Default / Autodetect */
|
||||||
meshtastic_Config_DisplayConfig_OledType_OLED_SH1106 = 2,
|
meshtastic_Config_DisplayConfig_OledType_OLED_SH1106 = 2,
|
||||||
/* Can not be auto detected but set by proto. Used for 128x128 screens */
|
|
||||||
meshtastic_Config_DisplayConfig_OledType_OLED_SH1107 = 3,
|
|
||||||
/* Can not be auto detected but set by proto. Used for 128x64 screens */
|
/* Can not be auto detected but set by proto. Used for 128x64 screens */
|
||||||
meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_64 = 4
|
meshtastic_Config_DisplayConfig_OledType_OLED_SH1107 = 3,
|
||||||
|
/* Can not be auto detected but set by proto. Used for 128x128 screens */
|
||||||
|
meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_128 = 4
|
||||||
} meshtastic_Config_DisplayConfig_OledType;
|
} meshtastic_Config_DisplayConfig_OledType;
|
||||||
|
|
||||||
typedef enum _meshtastic_Config_DisplayConfig_DisplayMode {
|
typedef enum _meshtastic_Config_DisplayConfig_DisplayMode {
|
||||||
@@ -682,8 +682,8 @@ extern "C" {
|
|||||||
#define _meshtastic_Config_DisplayConfig_DisplayUnits_ARRAYSIZE ((meshtastic_Config_DisplayConfig_DisplayUnits)(meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL+1))
|
#define _meshtastic_Config_DisplayConfig_DisplayUnits_ARRAYSIZE ((meshtastic_Config_DisplayConfig_DisplayUnits)(meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL+1))
|
||||||
|
|
||||||
#define _meshtastic_Config_DisplayConfig_OledType_MIN meshtastic_Config_DisplayConfig_OledType_OLED_AUTO
|
#define _meshtastic_Config_DisplayConfig_OledType_MIN meshtastic_Config_DisplayConfig_OledType_OLED_AUTO
|
||||||
#define _meshtastic_Config_DisplayConfig_OledType_MAX meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_64
|
#define _meshtastic_Config_DisplayConfig_OledType_MAX meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_128
|
||||||
#define _meshtastic_Config_DisplayConfig_OledType_ARRAYSIZE ((meshtastic_Config_DisplayConfig_OledType)(meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_64+1))
|
#define _meshtastic_Config_DisplayConfig_OledType_ARRAYSIZE ((meshtastic_Config_DisplayConfig_OledType)(meshtastic_Config_DisplayConfig_OledType_OLED_SH1107_128_128+1))
|
||||||
|
|
||||||
#define _meshtastic_Config_DisplayConfig_DisplayMode_MIN meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT
|
#define _meshtastic_Config_DisplayConfig_DisplayMode_MIN meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT
|
||||||
#define _meshtastic_Config_DisplayConfig_DisplayMode_MAX meshtastic_Config_DisplayConfig_DisplayMode_COLOR
|
#define _meshtastic_Config_DisplayConfig_DisplayMode_MAX meshtastic_Config_DisplayConfig_DisplayMode_COLOR
|
||||||
|
|||||||
@@ -99,7 +99,9 @@ typedef enum _meshtastic_TelemetrySensorType {
|
|||||||
/* Sensirion SFA30 Formaldehyde sensor */
|
/* Sensirion SFA30 Formaldehyde sensor */
|
||||||
meshtastic_TelemetrySensorType_SFA30 = 42,
|
meshtastic_TelemetrySensorType_SFA30 = 42,
|
||||||
/* SEN5X PM SENSORS */
|
/* SEN5X PM SENSORS */
|
||||||
meshtastic_TelemetrySensorType_SEN5X = 43
|
meshtastic_TelemetrySensorType_SEN5X = 43,
|
||||||
|
/* TSL2561 light sensor */
|
||||||
|
meshtastic_TelemetrySensorType_TSL2561 = 44
|
||||||
} meshtastic_TelemetrySensorType;
|
} meshtastic_TelemetrySensorType;
|
||||||
|
|
||||||
/* Struct definitions */
|
/* Struct definitions */
|
||||||
@@ -434,8 +436,8 @@ extern "C" {
|
|||||||
|
|
||||||
/* Helper constants for enums */
|
/* Helper constants for enums */
|
||||||
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
|
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
|
||||||
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_SEN5X
|
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_TSL2561
|
||||||
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_SEN5X+1))
|
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_TSL2561+1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -505,7 +505,9 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
|||||||
if (mp.decoded.want_response && !myReply) {
|
if (mp.decoded.want_response && !myReply) {
|
||||||
myReply = allocErrorResponse(meshtastic_Routing_Error_NONE, &mp);
|
myReply = allocErrorResponse(meshtastic_Routing_Error_NONE, &mp);
|
||||||
}
|
}
|
||||||
|
if (mp.pki_encrypted && myReply) {
|
||||||
|
myReply->pki_encrypted = true;
|
||||||
|
}
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -718,6 +720,13 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
|||||||
requiresReboot = false;
|
requiresReboot = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(ARCH_PORTDUINO)
|
||||||
|
// If running on portduino and using SimRadio, do not require reboot
|
||||||
|
if (SimRadio::instance) {
|
||||||
|
requiresReboot = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef RF95_FAN_EN
|
#ifdef RF95_FAN_EN
|
||||||
// Turn PA off if disabled by config
|
// Turn PA off if disabled by config
|
||||||
if (c.payload_variant.lora.pa_fan_disabled) {
|
if (c.payload_variant.lora.pa_fan_disabled) {
|
||||||
@@ -934,6 +943,9 @@ void AdminModule::handleGetOwner(const meshtastic_MeshPacket &req)
|
|||||||
res.which_payload_variant = meshtastic_AdminMessage_get_owner_response_tag;
|
res.which_payload_variant = meshtastic_AdminMessage_get_owner_response_tag;
|
||||||
setPassKey(&res);
|
setPassKey(&res);
|
||||||
myReply = allocDataProtobuf(res);
|
myReply = allocDataProtobuf(res);
|
||||||
|
if (req.pki_encrypted) {
|
||||||
|
myReply->pki_encrypted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1005,6 +1017,9 @@ void AdminModule::handleGetConfig(const meshtastic_MeshPacket &req, const uint32
|
|||||||
res.which_payload_variant = meshtastic_AdminMessage_get_config_response_tag;
|
res.which_payload_variant = meshtastic_AdminMessage_get_config_response_tag;
|
||||||
setPassKey(&res);
|
setPassKey(&res);
|
||||||
myReply = allocDataProtobuf(res);
|
myReply = allocDataProtobuf(res);
|
||||||
|
if (req.pki_encrypted) {
|
||||||
|
myReply->pki_encrypted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1092,6 +1107,9 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
|
|||||||
res.which_payload_variant = meshtastic_AdminMessage_get_module_config_response_tag;
|
res.which_payload_variant = meshtastic_AdminMessage_get_module_config_response_tag;
|
||||||
setPassKey(&res);
|
setPassKey(&res);
|
||||||
myReply = allocDataProtobuf(res);
|
myReply = allocDataProtobuf(res);
|
||||||
|
if (req.pki_encrypted) {
|
||||||
|
myReply->pki_encrypted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1116,6 +1134,9 @@ void AdminModule::handleGetNodeRemoteHardwarePins(const meshtastic_MeshPacket &r
|
|||||||
}
|
}
|
||||||
setPassKey(&r);
|
setPassKey(&r);
|
||||||
myReply = allocDataProtobuf(r);
|
myReply = allocDataProtobuf(r);
|
||||||
|
if (req.pki_encrypted) {
|
||||||
|
myReply->pki_encrypted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdminModule::handleGetDeviceMetadata(const meshtastic_MeshPacket &req)
|
void AdminModule::handleGetDeviceMetadata(const meshtastic_MeshPacket &req)
|
||||||
@@ -1125,6 +1146,9 @@ void AdminModule::handleGetDeviceMetadata(const meshtastic_MeshPacket &req)
|
|||||||
r.which_payload_variant = meshtastic_AdminMessage_get_device_metadata_response_tag;
|
r.which_payload_variant = meshtastic_AdminMessage_get_device_metadata_response_tag;
|
||||||
setPassKey(&r);
|
setPassKey(&r);
|
||||||
myReply = allocDataProtobuf(r);
|
myReply = allocDataProtobuf(r);
|
||||||
|
if (req.pki_encrypted) {
|
||||||
|
myReply->pki_encrypted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdminModule::handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &req)
|
void AdminModule::handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &req)
|
||||||
@@ -1193,6 +1217,9 @@ void AdminModule::handleGetDeviceConnectionStatus(const meshtastic_MeshPacket &r
|
|||||||
r.which_payload_variant = meshtastic_AdminMessage_get_device_connection_status_response_tag;
|
r.which_payload_variant = meshtastic_AdminMessage_get_device_connection_status_response_tag;
|
||||||
setPassKey(&r);
|
setPassKey(&r);
|
||||||
myReply = allocDataProtobuf(r);
|
myReply = allocDataProtobuf(r);
|
||||||
|
if (req.pki_encrypted) {
|
||||||
|
myReply->pki_encrypted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdminModule::handleGetChannel(const meshtastic_MeshPacket &req, uint32_t channelIndex)
|
void AdminModule::handleGetChannel(const meshtastic_MeshPacket &req, uint32_t channelIndex)
|
||||||
@@ -1204,6 +1231,9 @@ void AdminModule::handleGetChannel(const meshtastic_MeshPacket &req, uint32_t ch
|
|||||||
r.which_payload_variant = meshtastic_AdminMessage_get_channel_response_tag;
|
r.which_payload_variant = meshtastic_AdminMessage_get_channel_response_tag;
|
||||||
setPassKey(&r);
|
setPassKey(&r);
|
||||||
myReply = allocDataProtobuf(r);
|
myReply = allocDataProtobuf(r);
|
||||||
|
if (req.pki_encrypted) {
|
||||||
|
myReply->pki_encrypted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1213,6 +1243,9 @@ void AdminModule::handleGetDeviceUIConfig(const meshtastic_MeshPacket &req)
|
|||||||
r.which_payload_variant = meshtastic_AdminMessage_get_ui_config_response_tag;
|
r.which_payload_variant = meshtastic_AdminMessage_get_ui_config_response_tag;
|
||||||
r.get_ui_config_response = uiconfig;
|
r.get_ui_config_response = uiconfig;
|
||||||
myReply = allocDataProtobuf(r);
|
myReply = allocDataProtobuf(r);
|
||||||
|
if (req.pki_encrypted) {
|
||||||
|
myReply->pki_encrypted = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdminModule::reboot(int32_t seconds)
|
void AdminModule::reboot(int32_t seconds)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "buzz/BuzzerFeedbackThread.h"
|
#include "buzz/BuzzerFeedbackThread.h"
|
||||||
#include "input/ExpressLRSFiveWay.h"
|
#include "input/ExpressLRSFiveWay.h"
|
||||||
#include "input/InputBroker.h"
|
#include "input/InputBroker.h"
|
||||||
|
#include "input/RotaryEncoderImpl.h"
|
||||||
#include "input/RotaryEncoderInterruptImpl1.h"
|
#include "input/RotaryEncoderInterruptImpl1.h"
|
||||||
#include "input/SerialKeyboardImpl.h"
|
#include "input/SerialKeyboardImpl.h"
|
||||||
#include "input/TrackballInterruptImpl1.h"
|
#include "input/TrackballInterruptImpl1.h"
|
||||||
@@ -103,6 +104,10 @@
|
|||||||
#include "modules/DropzoneModule.h"
|
#include "modules/DropzoneModule.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !MESHTASTIC_EXCLUDE_ZPS
|
||||||
|
#include "modules/esp32/ZPSModule.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else)
|
* Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else)
|
||||||
*/
|
*/
|
||||||
@@ -149,6 +154,9 @@ void setupModules()
|
|||||||
#if !MESHTASTIC_EXCLUDE_DROPZONE
|
#if !MESHTASTIC_EXCLUDE_DROPZONE
|
||||||
dropzoneModule = new DropzoneModule();
|
dropzoneModule = new DropzoneModule();
|
||||||
#endif
|
#endif
|
||||||
|
#if !MESHTASTIC_EXCLUDE_ZPS
|
||||||
|
zpsModule = new ZPSModule();
|
||||||
|
#endif
|
||||||
#if !MESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE
|
#if !MESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE
|
||||||
new GenericThreadModule();
|
new GenericThreadModule();
|
||||||
#endif
|
#endif
|
||||||
@@ -170,11 +178,20 @@ void setupModules()
|
|||||||
delete rotaryEncoderInterruptImpl1;
|
delete rotaryEncoderInterruptImpl1;
|
||||||
rotaryEncoderInterruptImpl1 = nullptr;
|
rotaryEncoderInterruptImpl1 = nullptr;
|
||||||
}
|
}
|
||||||
|
#ifdef T_LORA_PAGER
|
||||||
|
// use a special FSM based rotary encoder version for T-LoRa Pager
|
||||||
|
rotaryEncoderImpl = new RotaryEncoderImpl();
|
||||||
|
if (!rotaryEncoderImpl->init()) {
|
||||||
|
delete rotaryEncoderImpl;
|
||||||
|
rotaryEncoderImpl = nullptr;
|
||||||
|
}
|
||||||
|
#else
|
||||||
upDownInterruptImpl1 = new UpDownInterruptImpl1();
|
upDownInterruptImpl1 = new UpDownInterruptImpl1();
|
||||||
if (!upDownInterruptImpl1->init()) {
|
if (!upDownInterruptImpl1->init()) {
|
||||||
delete upDownInterruptImpl1;
|
delete upDownInterruptImpl1;
|
||||||
upDownInterruptImpl1 = nullptr;
|
upDownInterruptImpl1 = nullptr;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
cardKbI2cImpl = new CardKbI2cImpl();
|
cardKbI2cImpl = new CardKbI2cImpl();
|
||||||
cardKbI2cImpl->init();
|
cardKbI2cImpl->init();
|
||||||
#ifdef INPUTBROKER_MATRIX_TYPE
|
#ifdef INPUTBROKER_MATRIX_TYPE
|
||||||
|
|||||||
@@ -45,6 +45,9 @@
|
|||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
#ifdef HELTEC_MESH_SOLAR
|
||||||
|
#include "meshSolarApp.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040)) && !defined(CONFIG_IDF_TARGET_ESP32S2) && \
|
||||||
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
!defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
@@ -60,8 +63,8 @@
|
|||||||
SerialModule *serialModule;
|
SerialModule *serialModule;
|
||||||
SerialModuleRadio *serialModuleRadio;
|
SerialModuleRadio *serialModuleRadio;
|
||||||
|
|
||||||
#if defined(TTGO_T_ECHO) || defined(T_ECHO_LITE) || defined(CANARYONE) || defined(MESHLINK) || defined(ELECROW_ThinkNode_M1) || \
|
#if defined(TTGO_T_ECHO) || defined(CANARYONE) || defined(MESHLINK) || defined(ELECROW_ThinkNode_M1) || \
|
||||||
defined(ELECROW_ThinkNode_M5)
|
defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE)
|
||||||
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial") {}
|
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial") {}
|
||||||
static Print *serialPrint = &Serial;
|
static Print *serialPrint = &Serial;
|
||||||
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
|
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||||
@@ -78,7 +81,8 @@ size_t serialPayloadSize;
|
|||||||
bool SerialModule::isValidConfig(const meshtastic_ModuleConfig_SerialConfig &config)
|
bool SerialModule::isValidConfig(const meshtastic_ModuleConfig_SerialConfig &config)
|
||||||
{
|
{
|
||||||
if (config.override_console_serial_port && !IS_ONE_OF(config.mode, meshtastic_ModuleConfig_SerialConfig_Serial_Mode_NMEA,
|
if (config.override_console_serial_port && !IS_ONE_OF(config.mode, meshtastic_ModuleConfig_SerialConfig_Serial_Mode_NMEA,
|
||||||
meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO)) {
|
meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO,
|
||||||
|
meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MS_CONFIG)) {
|
||||||
const char *warning =
|
const char *warning =
|
||||||
"Invalid Serial config: override console serial port is only supported in NMEA and CalTopo output-only modes.";
|
"Invalid Serial config: override console serial port is only supported in NMEA and CalTopo output-only modes.";
|
||||||
LOG_ERROR(warning);
|
LOG_ERROR(warning);
|
||||||
@@ -241,7 +245,17 @@ int32_t SerialModule::runOnce()
|
|||||||
else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) {
|
else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) {
|
||||||
processWXSerial();
|
processWXSerial();
|
||||||
|
|
||||||
} else {
|
}
|
||||||
|
#if defined(HELTEC_MESH_SOLAR)
|
||||||
|
else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MS_CONFIG)) {
|
||||||
|
serialPayloadSize = Serial.readBytes(serialBytes, sizeof(serialBytes) - 1);
|
||||||
|
// If the parsing fails, the following parsing will be performed.
|
||||||
|
if ((serialPayloadSize > 0) && (meshSolarCmdHandle(serialBytes) != 0)) {
|
||||||
|
return runOncePart(serialBytes, serialPayloadSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32C6)
|
#if defined(CONFIG_IDF_TARGET_ESP32C6)
|
||||||
while (Serial1.available()) {
|
while (Serial1.available()) {
|
||||||
serialPayloadSize = Serial1.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
serialPayloadSize = Serial1.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
|
||||||
|
|||||||
419
src/modules/esp32/ZPSModule.cpp
Normal file
419
src/modules/esp32/ZPSModule.cpp
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
/*
|
||||||
|
* ZPS - Zero-GPS Positioning System for standalone Meshtastic devices
|
||||||
|
* - experimental tools for estimating own position without a GPS -
|
||||||
|
*
|
||||||
|
* Copyright 2021 all rights reserved by https://github.com/a-f-G-U-C
|
||||||
|
* Released under GPL v3 (see LICENSE file for details)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ZPSModule.h"
|
||||||
|
#include "Default.h"
|
||||||
|
#include "MeshService.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
|
#include "NodeStatus.h"
|
||||||
|
#include "Router.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "gps/RTC.h"
|
||||||
|
#include <WiFi.h>
|
||||||
|
|
||||||
|
#if !defined(MESHTASTIC_EXCLUDE_BLUETOOTH)
|
||||||
|
|
||||||
|
#include "NimBLEDevice.h"
|
||||||
|
|
||||||
|
#define BLE_MAX_REC 15
|
||||||
|
#define BLE_NO_RESULTS -1 // Indicates a BLE scan is in progress
|
||||||
|
|
||||||
|
uint8_t bleCounter = 0; // used internally by the ble scanner
|
||||||
|
uint64_t bleResult[BLE_MAX_REC + 1];
|
||||||
|
int bleResSize = BLE_NO_RESULTS;
|
||||||
|
|
||||||
|
uint64_t scanStart = 0;
|
||||||
|
|
||||||
|
ZPSModule *zpsModule;
|
||||||
|
|
||||||
|
// Mini BLE scanner, NIMBLE based and modelled loosely after the Wifi scanner
|
||||||
|
static int ble_scan(uint32_t duration, bool passive = true, bool dedup = true);
|
||||||
|
|
||||||
|
// ZPSModule::ZPSModule()
|
||||||
|
// : ProtobufModule("ZPS", ZPS_PORTNUM, Position_fields), concurrency::OSThread("ZPSModule")
|
||||||
|
ZPSModule::ZPSModule() : SinglePortModule("ZPS", ZPS_PORTNUM), concurrency::OSThread("ZPSModule")
|
||||||
|
{
|
||||||
|
setIntervalFromNow(ZPS_STARTUP_DELAY); // Delay startup by 10 seconds, no need to race :)
|
||||||
|
|
||||||
|
wantBSS = true;
|
||||||
|
wantBLE = true;
|
||||||
|
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.disconnect();
|
||||||
|
WiFi.scanNetworks(true, true); // nonblock, showhidden
|
||||||
|
scanState = SCAN_BSS_RUN;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessMessage ZPSModule::handleReceived(const meshtastic_MeshPacket &mp)
|
||||||
|
{
|
||||||
|
meshtastic_Position pos = meshtastic_Position_init_default;
|
||||||
|
|
||||||
|
auto &pd = mp.decoded;
|
||||||
|
uint8_t nRecs = pd.payload.size >> 3;
|
||||||
|
|
||||||
|
LOG_DEBUG("handleReceived %s 0x%0x->0x%0x, id=0x%x, port=%d, len=%d, rec=%d\n", name, mp.from, mp.to, mp.id, pd.portnum,
|
||||||
|
pd.payload.size, nRecs);
|
||||||
|
if (nRecs > ZPS_DATAPKT_MAXITEMS)
|
||||||
|
nRecs = ZPS_DATAPKT_MAXITEMS;
|
||||||
|
memcpy(&netData, pd.payload.bytes, nRecs << 3);
|
||||||
|
|
||||||
|
// Currently we are unable to act as a position server, so we're
|
||||||
|
// not interested in broadcasts (this will change later)
|
||||||
|
if (mp.to != nodeDB->getNodeNum()) {
|
||||||
|
// Message is not for us, won't process
|
||||||
|
return ProcessMessage::CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ZPS_EXTRAVERBOSE
|
||||||
|
for (int i = 0; i < nRecs; i++) {
|
||||||
|
LOG_DEBUG("ZPS[%d]: %08x"
|
||||||
|
"%08x\n",
|
||||||
|
i, (uint32_t)(netData[i] >> 32), (uint32_t)netData[i]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((netData[0] & 0x800000000000) && (nRecs >= 2)) {
|
||||||
|
// message contains a position
|
||||||
|
pos.PDOP = (netData[0] >> 40) & 0x7f;
|
||||||
|
pos.timestamp = netData[0] & 0xffffffff;
|
||||||
|
// second int64 encodes lat and lon
|
||||||
|
pos.longitude_i = (int32_t)(netData[1] & 0xffffffff);
|
||||||
|
pos.latitude_i = (int32_t)((netData[1] >> 32) & 0xffffffff);
|
||||||
|
|
||||||
|
// FIXME should be conditional, to ensure we don't overwrite a good GPS fix!
|
||||||
|
LOG_DEBUG("ZPS lat/lon/dop/pts %d/%d/%d/%d\n", pos.latitude_i, pos.longitude_i, pos.PDOP, pos.timestamp);
|
||||||
|
|
||||||
|
// Some required fields
|
||||||
|
pos.time = getTime();
|
||||||
|
pos.location_source = meshtastic_Position_LocSource_LOC_EXTERNAL;
|
||||||
|
|
||||||
|
// don't update position if my gps fix is valid
|
||||||
|
if (nodeDB->hasValidPosition(nodeDB->getMeshNode(nodeDB->getNodeNum()))) {
|
||||||
|
LOG_DEBUG("ZPSModule::handleReceived: ignoring position update, GPS is valid\n");
|
||||||
|
return ProcessMessage::CONTINUE;
|
||||||
|
}
|
||||||
|
nodeDB->updatePosition(nodeDB->getNodeNum(), pos);
|
||||||
|
} else {
|
||||||
|
// nothing we can do - for now
|
||||||
|
return ProcessMessage::CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||||
|
}
|
||||||
|
|
||||||
|
meshtastic_MeshPacket *ZPSModule::allocReply()
|
||||||
|
{
|
||||||
|
meshtastic_MeshPacket *p = allocDataPacket();
|
||||||
|
p->decoded.payload.size = (netRecs + 2) << 3; // actually can be only +1 if no GPS data
|
||||||
|
|
||||||
|
LOG_DEBUG("Allocating dataPacket for %d items, %d bytes\n", netRecs, p->decoded.payload.size);
|
||||||
|
memcpy(p->decoded.payload.bytes, &netData, p->decoded.payload.size);
|
||||||
|
|
||||||
|
return (p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZPSModule::sendDataPacket(NodeNum dest, bool wantReplies)
|
||||||
|
{
|
||||||
|
// cancel any not yet sent (now stale) position packets
|
||||||
|
if (prevPacketId)
|
||||||
|
service->cancelSending(prevPacketId);
|
||||||
|
|
||||||
|
meshtastic_MeshPacket *p = allocReply();
|
||||||
|
p->to = dest;
|
||||||
|
p->decoded.portnum = meshtastic_PortNum_ZPS_APP;
|
||||||
|
p->decoded.want_response = wantReplies;
|
||||||
|
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||||
|
prevPacketId = p->id;
|
||||||
|
|
||||||
|
service->sendToMesh(p, RX_SRC_LOCAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t ZPSModule::runOnce()
|
||||||
|
{
|
||||||
|
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||||
|
assert(node);
|
||||||
|
|
||||||
|
// LOG_DEBUG("ZPSModule::runOnce() START, scanState: %d\n", (int) scanState);
|
||||||
|
|
||||||
|
int numWifi = 0;
|
||||||
|
|
||||||
|
if (scanState == SCAN_BSS_RUN) {
|
||||||
|
// check completion status of any running Wifi scan
|
||||||
|
numWifi = WiFi.scanComplete();
|
||||||
|
|
||||||
|
if (numWifi >= 0) {
|
||||||
|
// scan is complete
|
||||||
|
LOG_DEBUG("%d BSS found\n", numWifi);
|
||||||
|
LOG_DEBUG("BSS scan done in %d millis\n", millis() - scanStart);
|
||||||
|
|
||||||
|
if (wantBSS && haveBSS) {
|
||||||
|
// old data exists, overwrite it
|
||||||
|
netRecs = 0;
|
||||||
|
haveBSS = haveBLE = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < numWifi; i++) {
|
||||||
|
// pack each Wifi network record into a 64-bit int
|
||||||
|
uint64_t netBytes = encodeBSS(WiFi.BSSID(i), WiFi.channel(i), abs(WiFi.RSSI(i)));
|
||||||
|
|
||||||
|
if (wantBSS) {
|
||||||
|
// load into outbound array if needed
|
||||||
|
outBufAdd(netBytes);
|
||||||
|
haveBSS = true;
|
||||||
|
}
|
||||||
|
#ifdef ZPS_EXTRAVERBOSE
|
||||||
|
LOG_DEBUG("BSS[%02d]: %08x"
|
||||||
|
"%08x\n",
|
||||||
|
i, (uint32_t)(netBytes >> 32), (uint32_t)netBytes);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFi.scanDelete();
|
||||||
|
scanState = SCAN_BSS_DONE;
|
||||||
|
|
||||||
|
#ifdef ZPS_EXTRAVERBOSE
|
||||||
|
} else if (numWifi == -1) {
|
||||||
|
// LOG_DEBUG("BSS scan in-progress\n");
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("BSS scan state=%d\n", numWifi);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((scanState == SCAN_BLE_RUN) && (bleResSize >= 0)) {
|
||||||
|
// completion status checked above (bleResSize >= 0)
|
||||||
|
LOG_DEBUG("BLE scan done in %d millis\n", millis() - scanStart);
|
||||||
|
scanState = SCAN_BLE_DONE;
|
||||||
|
|
||||||
|
if (wantBLE && haveBLE) {
|
||||||
|
// old data exists, overwrite it
|
||||||
|
netRecs = 0;
|
||||||
|
haveBSS = haveBLE = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < bleResSize; i++) {
|
||||||
|
// load data into output array if needed
|
||||||
|
if (wantBLE) {
|
||||||
|
outBufAdd(bleResult[i]);
|
||||||
|
haveBLE = true;
|
||||||
|
}
|
||||||
|
#ifdef ZPS_EXTRAVERBOSE
|
||||||
|
LOG_DEBUG("BLE[%d]: %08x"
|
||||||
|
"%08x\n",
|
||||||
|
i, (uint32_t)(bleResult[i] >> 32), (uint32_t)bleResult[i]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the counter once we're done with the dataset
|
||||||
|
bleResSize = BLE_NO_RESULTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we finished assembling that packet? Then send it out
|
||||||
|
if ((wantBSS == haveBSS) && (wantBLE == haveBLE) &&
|
||||||
|
airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
|
||||||
|
airTime->isTxAllowedAirUtil() &&
|
||||||
|
(lastSend == 0 || millis() - lastSend >= Default::getConfiguredOrDefaultMsScaled(config.position.position_broadcast_secs,
|
||||||
|
default_broadcast_interval_secs,
|
||||||
|
nodeStatus->getNumOnline()))) {
|
||||||
|
|
||||||
|
haveBSS = haveBLE = false;
|
||||||
|
sendDataPacket(NODENUM_BROADCAST, false); // no replies
|
||||||
|
lastSend = millis();
|
||||||
|
netRecs = 0; // reset packet
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* State machine transitions
|
||||||
|
*
|
||||||
|
* FIXME could be managed better, for example: check if we require
|
||||||
|
* each type of scan (wantBSS/wantBLE), and if not, don't start it!
|
||||||
|
*/
|
||||||
|
if (scanState == SCAN_BLE_DONE) {
|
||||||
|
// BLE done, transition to BSS scanning
|
||||||
|
scanStart = millis();
|
||||||
|
LOG_DEBUG("BSS scan start t=%d\n", scanStart);
|
||||||
|
if (WiFi.scanNetworks(true, true) == WIFI_SCAN_RUNNING) // nonblock, showhidden
|
||||||
|
scanState = SCAN_BSS_RUN;
|
||||||
|
|
||||||
|
} else if (scanState == SCAN_BSS_DONE) {
|
||||||
|
// BSS done, transition to BLE scanning
|
||||||
|
scanStart = millis();
|
||||||
|
LOG_DEBUG("BLE scan start t=%d\n", scanStart);
|
||||||
|
if (ble_scan(ZPS_BLE_SCANTIME) == 0)
|
||||||
|
scanState = SCAN_BLE_RUN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_DEBUG("ZPSModule::runOnce() DONE, scanState=%d\n", scanState);
|
||||||
|
if ((scanState == SCAN_BSS_RUN) || (scanState == SCAN_BLE_RUN)) {
|
||||||
|
return 1000; // scan in progress, re-check soon
|
||||||
|
}
|
||||||
|
|
||||||
|
return 5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t encodeBSS(uint8_t *bssid, uint8_t chan, uint8_t absRSSI)
|
||||||
|
{
|
||||||
|
uint64_t netBytes = absRSSI & 0xff;
|
||||||
|
netBytes <<= 8;
|
||||||
|
netBytes |= (chan & 0xff);
|
||||||
|
|
||||||
|
for (uint8_t b = 0; b < 6; b++) {
|
||||||
|
netBytes <<= 8;
|
||||||
|
netBytes |= bssid[b];
|
||||||
|
}
|
||||||
|
|
||||||
|
return netBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t encodeBLE(uint8_t *addr, uint8_t absRSSI)
|
||||||
|
{
|
||||||
|
uint64_t netBytes = absRSSI & 0xff;
|
||||||
|
netBytes <<= 8;
|
||||||
|
netBytes |= 0xff; // "channel" byte reserved in BLE records
|
||||||
|
|
||||||
|
for (uint8_t b = 0; b < 6; b++) {
|
||||||
|
netBytes <<= 8;
|
||||||
|
netBytes |= addr[5 - b] & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return netBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler
|
||||||
|
*/
|
||||||
|
static int ble_gap_event(struct ble_gap_event *event, void *arg)
|
||||||
|
{
|
||||||
|
// Adverts matching certain patterns are useless for positioning purposes
|
||||||
|
// (ephemeral MAC etc), so try excluding them if possible
|
||||||
|
//
|
||||||
|
// TODO: Expand the list of reject patterns for BLE adverts.
|
||||||
|
// There are likely more than 10 patterns to test and reject, including most Apple devices and others.
|
||||||
|
//
|
||||||
|
// TODO: Implement full packet search for reject patterns (use memmem() or similar),
|
||||||
|
// not just at the beginning (currently uses memcmp()).
|
||||||
|
|
||||||
|
const uint8_t rejPat[] = {0x1e, 0xff, 0x06, 0x00, 0x01}; // one of many
|
||||||
|
|
||||||
|
struct ble_hs_adv_fields fields;
|
||||||
|
int rc;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
uint64_t netBytes = 0;
|
||||||
|
|
||||||
|
switch (event->type) {
|
||||||
|
case BLE_GAP_EVENT_DISC:
|
||||||
|
// called once for every BLE advert received
|
||||||
|
rc = ble_hs_adv_parse_fields(&fields, event->disc.data, event->disc.length_data);
|
||||||
|
if (rc != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (bleResSize != BLE_NO_RESULTS)
|
||||||
|
// as far as we know, we're not in the middle of a BLE scan!
|
||||||
|
LOG_DEBUG("Unexpected BLE_GAP_EVENT_DISC!\n");
|
||||||
|
|
||||||
|
#ifdef ZPS_EXTRAVERBOSE
|
||||||
|
// Dump the advertisement packet
|
||||||
|
DEBUG_PORT.hexDump("DEBUG", (unsigned char *)event->disc.data, event->disc.length_data);
|
||||||
|
#endif
|
||||||
|
// Reject beacons known to be unreliable (ephemeral etc)
|
||||||
|
if (memcmp(event->disc.data, rejPat, sizeof(rejPat)) == 0) {
|
||||||
|
LOG_DEBUG("(BLE item filtered by pattern)\n");
|
||||||
|
return 0; // Processing-wise, it's still a success
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// STORE THE RESULTS IN A SORTED LIST
|
||||||
|
//
|
||||||
|
|
||||||
|
// first, pack each BLE item reading into a 64-bit int
|
||||||
|
netBytes = encodeBLE(event->disc.addr.val, abs(event->disc.rssi));
|
||||||
|
|
||||||
|
// SOME DUPLICATES SURVIVE through filter_duplicates = 1, catch them here
|
||||||
|
// Duplicate filtering is now handled in the sorting loop below,
|
||||||
|
// but right now we write for clarity not optimization
|
||||||
|
for (i = 0; i < bleCounter; i++) {
|
||||||
|
if ((bleResult[i] & 0xffffffffffff) == (netBytes & 0xffffffffffff)) {
|
||||||
|
LOG_DEBUG("(BLE duplicate filtered)\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ZPS_EXTRAVERBOSE
|
||||||
|
// redundant extraverbosity, but I need it for duplicate hunting
|
||||||
|
LOG_DEBUG("BL_[%02d]: %08x"
|
||||||
|
"%08x\n",
|
||||||
|
bleCounter, (uint32_t)(netBytes >> 32), (uint32_t)netBytes);
|
||||||
|
#endif
|
||||||
|
// then insert item into a list (up to BLE_MAX_REC records), sorted by RSSI
|
||||||
|
for (i = 0; i < bleCounter; i++) {
|
||||||
|
// find first element greater than ours, that will be our insertion point
|
||||||
|
if (bleResult[i] > netBytes)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// any other records move down one position to vacate res[i]
|
||||||
|
for (int j = bleCounter; j > i; j--)
|
||||||
|
bleResult[j] = bleResult[j - 1];
|
||||||
|
// write new element at insertion point
|
||||||
|
bleResult[i] = netBytes;
|
||||||
|
|
||||||
|
// advance tail of list, but not beyond limit
|
||||||
|
if (bleCounter < BLE_MAX_REC)
|
||||||
|
bleCounter++;
|
||||||
|
|
||||||
|
return 0; // SUCCESS
|
||||||
|
|
||||||
|
case BLE_GAP_EVENT_DISC_COMPLETE:
|
||||||
|
LOG_DEBUG("EVENT_DISC_COMPLETE in %d millis\n", (millis() - scanStart));
|
||||||
|
LOG_DEBUG("%d BLE found\n", bleCounter);
|
||||||
|
bleResSize = bleCounter;
|
||||||
|
|
||||||
|
bleCounter = 0; // reset counter
|
||||||
|
return 0; // SUCCESS
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0; // SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiates the GAP general discovery procedure (non-blocking)
|
||||||
|
*/
|
||||||
|
static int ble_scan(uint32_t duration, bool passive, bool dedup)
|
||||||
|
{
|
||||||
|
uint8_t own_addr_type;
|
||||||
|
struct ble_gap_disc_params disc_params;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
// Figure out address type to use
|
||||||
|
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||||
|
if (rc != 0) {
|
||||||
|
LOG_DEBUG("error determining address type; rc=%d\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scanning parameters, these are mostly default
|
||||||
|
disc_params.itvl = 0;
|
||||||
|
disc_params.window = 0;
|
||||||
|
disc_params.filter_policy = 0;
|
||||||
|
disc_params.limited = 0;
|
||||||
|
|
||||||
|
// These two params are the more interesting ones
|
||||||
|
disc_params.filter_duplicates = dedup; // self-explanatory
|
||||||
|
disc_params.passive = passive; // passive uses less power
|
||||||
|
|
||||||
|
// Start scanning process (non-blocking) and return
|
||||||
|
rc = ble_gap_disc(own_addr_type, duration, &disc_params, ble_gap_event, NULL);
|
||||||
|
if (rc != 0) {
|
||||||
|
LOG_DEBUG("error initiating GAP discovery; rc=%d\n", rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||||
86
src/modules/esp32/ZPSModule.h
Normal file
86
src/modules/esp32/ZPSModule.h
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "SinglePortModule.h"
|
||||||
|
#include "concurrency/OSThread.h"
|
||||||
|
#include "gps/RTC.h"
|
||||||
|
|
||||||
|
#define ZPS_PORTNUM meshtastic_PortNum_ZPS_APP
|
||||||
|
|
||||||
|
#define ZPS_DATAPKT_MAXITEMS 20 // max number of records to pack in an outbound packet (~10)
|
||||||
|
#define ZPS_STARTUP_DELAY 10000 // Module startup delay in millis
|
||||||
|
|
||||||
|
// Duration of a BLE scan in millis.
|
||||||
|
// We want this number to be SLIGHTLY UNDER an integer number of seconds,
|
||||||
|
// to be able to catch the result as fresh as possible on a 1-second polling loop
|
||||||
|
#define ZPS_BLE_SCANTIME 2900 // millis
|
||||||
|
|
||||||
|
enum SCANSTATE { SCAN_NONE, SCAN_BSS_RUN, SCAN_BSS_DONE, SCAN_BLE_RUN, SCAN_BLE_DONE };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data packing "compression" functions
|
||||||
|
* Ingest a WiFi BSSID, channel and RSSI (or BLE address and RSSI)
|
||||||
|
* and encode them into a packed uint64
|
||||||
|
*/
|
||||||
|
uint64_t encodeBSS(uint8_t *bssid, uint8_t chan, uint8_t absRSSI);
|
||||||
|
uint64_t encodeBLE(uint8_t *addr, uint8_t absRSSI);
|
||||||
|
|
||||||
|
class ZPSModule : public SinglePortModule, private concurrency::OSThread
|
||||||
|
{
|
||||||
|
/// The id of the last packet we sent, to allow us to cancel it if we make something fresher
|
||||||
|
PacketId prevPacketId = 0;
|
||||||
|
|
||||||
|
/// We limit our broadcasts to a max rate
|
||||||
|
uint32_t lastSend = 0;
|
||||||
|
|
||||||
|
bool wantBSS = true;
|
||||||
|
bool haveBSS = false;
|
||||||
|
|
||||||
|
bool wantBLE = true;
|
||||||
|
bool haveBLE = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
* name is for debugging output
|
||||||
|
*/
|
||||||
|
ZPSModule();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send our radio environment data into the mesh
|
||||||
|
*/
|
||||||
|
void sendDataPacket(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Called to handle a particular incoming message
|
||||||
|
@return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||||
|
*/
|
||||||
|
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp);
|
||||||
|
|
||||||
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
|
* so that subclasses can (optionally) send a response back to the original sender. */
|
||||||
|
virtual meshtastic_MeshPacket *allocReply();
|
||||||
|
|
||||||
|
/** Does our periodic broadcast */
|
||||||
|
virtual int32_t runOnce();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// outbound data packet staging buffer and record counter
|
||||||
|
uint64_t netData[ZPS_DATAPKT_MAXITEMS + 2] = {0};
|
||||||
|
uint8_t netRecs = 0;
|
||||||
|
|
||||||
|
// mini state machine to alternate between BSS(Wifi) and BLE scanning
|
||||||
|
SCANSTATE scanState = SCAN_NONE;
|
||||||
|
|
||||||
|
inline void outBufAdd(uint64_t netBytes)
|
||||||
|
{
|
||||||
|
// If this is the first record, initialize the header with the current time and reset the record count.
|
||||||
|
if (!netRecs) {
|
||||||
|
netData[0] = getTime();
|
||||||
|
netData[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// push to buffer and update counter
|
||||||
|
if (netRecs < ZPS_DATAPKT_MAXITEMS)
|
||||||
|
netData[2 + (netRecs++)] = netBytes;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ZPSModule *zpsModule;
|
||||||
@@ -279,6 +279,8 @@ struct PubSubConfig {
|
|||||||
|
|
||||||
// Defaults
|
// Defaults
|
||||||
static constexpr uint16_t defaultPort = 1883;
|
static constexpr uint16_t defaultPort = 1883;
|
||||||
|
static constexpr uint16_t defaultPortTls = 8883;
|
||||||
|
|
||||||
uint16_t serverPort = defaultPort;
|
uint16_t serverPort = defaultPort;
|
||||||
String serverAddr = default_mqtt_address;
|
String serverAddr = default_mqtt_address;
|
||||||
const char *mqttUsername = default_mqtt_username;
|
const char *mqttUsername = default_mqtt_username;
|
||||||
@@ -641,7 +643,7 @@ bool MQTT::isValidConfig(const meshtastic_ModuleConfig_MQTTConfig &config, MQTTC
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bool defaultServer = isDefaultServer(parsed.serverAddr);
|
const bool defaultServer = isDefaultServer(parsed.serverAddr);
|
||||||
if (defaultServer && parsed.serverPort != PubSubConfig::defaultPort) {
|
if (defaultServer && !IS_ONE_OF(parsed.serverPort, PubSubConfig::defaultPort, PubSubConfig::defaultPortTls)) {
|
||||||
const char *warning = "Invalid MQTT config: default server address must not have a port specified";
|
const char *warning = "Invalid MQTT config: default server address must not have a port specified";
|
||||||
LOG_ERROR(warning);
|
LOG_ERROR(warning);
|
||||||
#if !IS_RUNNING_TESTS
|
#if !IS_RUNNING_TESTS
|
||||||
|
|||||||
@@ -192,6 +192,8 @@
|
|||||||
#define HW_VENDOR meshtastic_HardwareModel_LINK_32
|
#define HW_VENDOR meshtastic_HardwareModel_LINK_32
|
||||||
#elif defined(T_DECK_PRO)
|
#elif defined(T_DECK_PRO)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_T_DECK_PRO
|
#define HW_VENDOR meshtastic_HardwareModel_T_DECK_PRO
|
||||||
|
#elif defined(T_LORA_PAGER)
|
||||||
|
#define HW_VENDOR meshtastic_HardwareModel_T_LORA_PAGER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
27
src/platform/extra_variants/t_lora_pager/variant.cpp
Normal file
27
src/platform/extra_variants/t_lora_pager/variant.cpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#ifdef T_LORA_PAGER
|
||||||
|
|
||||||
|
#include "AudioBoard.h"
|
||||||
|
|
||||||
|
DriverPins PinsAudioBoardES8311;
|
||||||
|
AudioBoard board(AudioDriverES8311, PinsAudioBoardES8311);
|
||||||
|
|
||||||
|
// TLora Pager specific init
|
||||||
|
void lateInitVariant()
|
||||||
|
{
|
||||||
|
// AudioDriverLogger.begin(Serial, AudioDriverLogLevel::Debug);
|
||||||
|
// I2C: function, scl, sda
|
||||||
|
PinsAudioBoardES8311.addI2C(PinFunction::CODEC, Wire);
|
||||||
|
// I2S: function, mclk, bck, ws, data_out, data_in
|
||||||
|
PinsAudioBoardES8311.addI2S(PinFunction::CODEC, DAC_I2S_MCLK, DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT, DAC_I2S_DIN);
|
||||||
|
|
||||||
|
// configure codec
|
||||||
|
CodecConfig cfg;
|
||||||
|
cfg.input_device = ADC_INPUT_LINE1;
|
||||||
|
cfg.output_device = DAC_OUTPUT_ALL;
|
||||||
|
cfg.i2s.bits = BIT_LENGTH_16BITS;
|
||||||
|
cfg.i2s.rate = RATE_44K;
|
||||||
|
board.begin(cfg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -98,6 +98,8 @@
|
|||||||
#define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1_EINK
|
#define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1_EINK
|
||||||
#elif defined(SEEED_WIO_TRACKER_L1)
|
#elif defined(SEEED_WIO_TRACKER_L1)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1
|
#define HW_VENDOR meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1
|
||||||
|
#elif defined(HELTEC_MESH_SOLAR)
|
||||||
|
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_SOLAR
|
||||||
#else
|
#else
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_NRF52_UNKNOWN
|
#define HW_VENDOR meshtastic_HardwareModel_NRF52_UNKNOWN
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -323,7 +323,7 @@ void cpuDeepSleep(uint32_t msecToWake)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HELTEC_MESH_NODE_T114
|
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_MESH_SOLAR)
|
||||||
nrf_gpio_cfg_default(PIN_GPS_PPS);
|
nrf_gpio_cfg_default(PIN_GPS_PPS);
|
||||||
detachInterrupt(PIN_GPS_PPS);
|
detachInterrupt(PIN_GPS_PPS);
|
||||||
detachInterrupt(PIN_BUTTON1);
|
detachInterrupt(PIN_BUTTON1);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "linux/gpio/LinuxGPIOPin.h"
|
#include "linux/gpio/LinuxGPIOPin.h"
|
||||||
#include "meshUtils.h"
|
#include "meshUtils.h"
|
||||||
#include "yaml-cpp/yaml.h"
|
#include "yaml-cpp/yaml.h"
|
||||||
|
#include <ErriezCRC32.h>
|
||||||
#include <Utility.h>
|
#include <Utility.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <bluetooth/bluetooth.h>
|
#include <bluetooth/bluetooth.h>
|
||||||
@@ -29,11 +30,11 @@
|
|||||||
|
|
||||||
std::map<configNames, int> settingsMap;
|
std::map<configNames, int> settingsMap;
|
||||||
std::map<configNames, std::string> settingsStrings;
|
std::map<configNames, std::string> settingsStrings;
|
||||||
|
portduino_config_struct portduino_config;
|
||||||
std::ofstream traceFile;
|
std::ofstream traceFile;
|
||||||
Ch341Hal *ch341Hal = nullptr;
|
Ch341Hal *ch341Hal = nullptr;
|
||||||
char *configPath = nullptr;
|
char *configPath = nullptr;
|
||||||
char *optionMac = nullptr;
|
char *optionMac = nullptr;
|
||||||
bool forceSimulated = false;
|
|
||||||
bool verboseEnabled = false;
|
bool verboseEnabled = false;
|
||||||
|
|
||||||
const char *argp_program_version = optstr(APP_VERSION);
|
const char *argp_program_version = optstr(APP_VERSION);
|
||||||
@@ -66,7 +67,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
|||||||
configPath = arg;
|
configPath = arg;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
forceSimulated = true;
|
portduino_config.force_simradio = true;
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
optionMac = arg;
|
optionMac = arg;
|
||||||
@@ -189,7 +190,7 @@ void portduinoSetup()
|
|||||||
|
|
||||||
YAML::Node yamlConfig;
|
YAML::Node yamlConfig;
|
||||||
|
|
||||||
if (forceSimulated == true) {
|
if (portduino_config.force_simradio == true) {
|
||||||
settingsMap[use_simradio] = true;
|
settingsMap[use_simradio] = true;
|
||||||
} else if (configPath != nullptr) {
|
} else if (configPath != nullptr) {
|
||||||
if (loadConfig(configPath)) {
|
if (loadConfig(configPath)) {
|
||||||
@@ -253,16 +254,95 @@ void portduinoSetup()
|
|||||||
std::cout << "autoconf: Could not locate CH341 device" << std::endl;
|
std::cout << "autoconf: Could not locate CH341 device" << std::endl;
|
||||||
}
|
}
|
||||||
// Try Pi HAT+
|
// Try Pi HAT+
|
||||||
std::cout << "autoconf: Looking for Pi HAT+..." << std::endl;
|
if (strlen(autoconf_product) < 6) {
|
||||||
if (access("/proc/device-tree/hat/product", R_OK) == 0) {
|
std::cout << "autoconf: Looking for Pi HAT+..." << std::endl;
|
||||||
std::ifstream hatProductFile("/proc/device-tree/hat/product");
|
if (access("/proc/device-tree/hat/product", R_OK) == 0) {
|
||||||
if (hatProductFile.is_open()) {
|
std::ifstream hatProductFile("/proc/device-tree/hat/product");
|
||||||
hatProductFile.read(autoconf_product, 95);
|
if (hatProductFile.is_open()) {
|
||||||
hatProductFile.close();
|
hatProductFile.read(autoconf_product, 95);
|
||||||
|
hatProductFile.close();
|
||||||
|
}
|
||||||
|
std::cout << "autoconf: Found Pi HAT+ " << autoconf_product << " at /proc/device-tree/hat/product" << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "autoconf: Could not locate Pi HAT+ at /proc/device-tree/hat/product" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// attempt to load autoconf data from an EEPROM on 0x50
|
||||||
|
// RAK6421-13300-S1:aabbcc123456:5ba85807d92138b7519cfb60460573af:3061e8d8
|
||||||
|
// <model string>:mac address :<16 random unique bytes in hexidecimal> : crc32
|
||||||
|
// crc32 is calculated on the eeprom string up to but not including the final colon
|
||||||
|
if (strlen(autoconf_product) < 6) {
|
||||||
|
try {
|
||||||
|
char *mac_start = nullptr;
|
||||||
|
char *devID_start = nullptr;
|
||||||
|
char *crc32_start = nullptr;
|
||||||
|
Wire.begin();
|
||||||
|
Wire.beginTransmission(0x50);
|
||||||
|
Wire.write(0x0);
|
||||||
|
Wire.write(0x0);
|
||||||
|
Wire.endTransmission();
|
||||||
|
Wire.requestFrom((uint8_t)0x50, (uint8_t)75);
|
||||||
|
uint8_t i = 0;
|
||||||
|
delay(100);
|
||||||
|
std::string autoconf_raw;
|
||||||
|
while (Wire.available() && i < sizeof(autoconf_product)) {
|
||||||
|
autoconf_product[i] = Wire.read();
|
||||||
|
if (autoconf_product[i] == 0xff) {
|
||||||
|
autoconf_product[i] = 0x0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
autoconf_raw += autoconf_product[i];
|
||||||
|
if (autoconf_product[i] == ':') {
|
||||||
|
autoconf_product[i] = 0x0;
|
||||||
|
if (mac_start == nullptr) {
|
||||||
|
mac_start = autoconf_product + i + 1;
|
||||||
|
} else if (devID_start == nullptr) {
|
||||||
|
devID_start = autoconf_product + i + 1;
|
||||||
|
} else if (crc32_start == nullptr) {
|
||||||
|
crc32_start = autoconf_product + i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (crc32_start != nullptr && strlen(crc32_start) == 8) {
|
||||||
|
std::string crc32_str(crc32_start);
|
||||||
|
uint32_t crc32_value = 0;
|
||||||
|
|
||||||
|
// convert crc32 ascii to raw uint32
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
crc32_value += std::stoi(crc32_str.substr(j * 2, 2), nullptr, 16) << (3 - j) * 8;
|
||||||
|
}
|
||||||
|
std::cout << "autoconf: Found eeprom crc " << crc32_start << std::endl;
|
||||||
|
|
||||||
|
// set the autoconf string to blank and short circuit
|
||||||
|
if (crc32_value != crc32Buffer(autoconf_raw.c_str(), i - 9)) {
|
||||||
|
std::cout << "autoconf: crc32 mismatch, dropping " << std::endl;
|
||||||
|
autoconf_product[0] = 0x0;
|
||||||
|
} else {
|
||||||
|
std::cout << "autoconf: Found eeprom data " << autoconf_raw << std::endl;
|
||||||
|
if (mac_start != nullptr) {
|
||||||
|
std::cout << "autoconf: Found mac data " << mac_start << std::endl;
|
||||||
|
if (strlen(mac_start) == 12)
|
||||||
|
settingsStrings[mac_address] = std::string(mac_start);
|
||||||
|
}
|
||||||
|
if (devID_start != nullptr) {
|
||||||
|
std::cout << "autoconf: Found deviceid data " << devID_start << std::endl;
|
||||||
|
if (strlen(devID_start) == 32) {
|
||||||
|
std::string devID_str(devID_start);
|
||||||
|
for (int j = 0; j < 16; j++) {
|
||||||
|
portduino_config.device_id[j] = std::stoi(devID_str.substr(j * 2, 2), nullptr, 16);
|
||||||
|
}
|
||||||
|
portduino_config.has_device_id = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "autoconf: crc32 missing " << std::endl;
|
||||||
|
autoconf_product[0] = 0x0;
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
std::cout << "autoconf: Could not locate EEPROM" << std::endl;
|
||||||
}
|
}
|
||||||
std::cout << "autoconf: Found Pi HAT+ " << autoconf_product << " at /proc/device-tree/hat/product" << std::endl;
|
|
||||||
} else {
|
|
||||||
std::cout << "autoconf: Could not locate Pi HAT+ at /proc/device-tree/hat/product" << std::endl;
|
|
||||||
}
|
}
|
||||||
// Load the config file based on the product string
|
// Load the config file based on the product string
|
||||||
if (strlen(autoconf_product) > 0) {
|
if (strlen(autoconf_product) > 0) {
|
||||||
@@ -553,6 +633,48 @@ bool loadConfig(const char *configPath)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]) {
|
||||||
|
portduino_config.has_rfswitch_table = true;
|
||||||
|
portduino_config.rfswitch_table[0].mode = LR11x0::MODE_STBY;
|
||||||
|
portduino_config.rfswitch_table[1].mode = LR11x0::MODE_RX;
|
||||||
|
portduino_config.rfswitch_table[2].mode = LR11x0::MODE_TX;
|
||||||
|
portduino_config.rfswitch_table[3].mode = LR11x0::MODE_TX_HP;
|
||||||
|
portduino_config.rfswitch_table[4].mode = LR11x0::MODE_TX_HF;
|
||||||
|
portduino_config.rfswitch_table[5].mode = LR11x0::MODE_GNSS;
|
||||||
|
portduino_config.rfswitch_table[6].mode = LR11x0::MODE_WIFI;
|
||||||
|
portduino_config.rfswitch_table[7] = END_OF_MODE_TABLE;
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
|
||||||
|
// set up the pin array first
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]["pins"][i].as<std::string>("") == "DIO5")
|
||||||
|
portduino_config.rfswitch_dio_pins[i] = RADIOLIB_LR11X0_DIO5;
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]["pins"][i].as<std::string>("") == "DIO6")
|
||||||
|
portduino_config.rfswitch_dio_pins[i] = RADIOLIB_LR11X0_DIO6;
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]["pins"][i].as<std::string>("") == "DIO7")
|
||||||
|
portduino_config.rfswitch_dio_pins[i] = RADIOLIB_LR11X0_DIO7;
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]["pins"][i].as<std::string>("") == "DIO8")
|
||||||
|
portduino_config.rfswitch_dio_pins[i] = RADIOLIB_LR11X0_DIO8;
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]["pins"][i].as<std::string>("") == "DIO10")
|
||||||
|
portduino_config.rfswitch_dio_pins[i] = RADIOLIB_LR11X0_DIO10;
|
||||||
|
|
||||||
|
// now fill in the table
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]["MODE_STBY"][i].as<std::string>("") == "HIGH")
|
||||||
|
portduino_config.rfswitch_table[0].values[i] = HIGH;
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]["MODE_RX"][i].as<std::string>("") == "HIGH")
|
||||||
|
portduino_config.rfswitch_table[1].values[i] = HIGH;
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]["MODE_TX"][i].as<std::string>("") == "HIGH")
|
||||||
|
portduino_config.rfswitch_table[2].values[i] = HIGH;
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]["MODE_TX_HP"][i].as<std::string>("") == "HIGH")
|
||||||
|
portduino_config.rfswitch_table[3].values[i] = HIGH;
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]["MODE_TX_HF"][i].as<std::string>("") == "HIGH")
|
||||||
|
portduino_config.rfswitch_table[4].values[i] = HIGH;
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]["MODE_GNSS"][i].as<std::string>("") == "HIGH")
|
||||||
|
portduino_config.rfswitch_table[5].values[i] = HIGH;
|
||||||
|
if (yamlConfig["Lora"]["rfswitch_table"]["MODE_WIFI"][i].as<std::string>("") == "HIGH")
|
||||||
|
portduino_config.rfswitch_table[6].values[i] = HIGH;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (yamlConfig["GPIO"]) {
|
if (yamlConfig["GPIO"]) {
|
||||||
settingsMap[userButtonPin] = yamlConfig["GPIO"]["User"].as<int>(RADIOLIB_NC);
|
settingsMap[userButtonPin] = yamlConfig["GPIO"]["User"].as<int>(RADIOLIB_NC);
|
||||||
|
|||||||
@@ -3,16 +3,21 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "LR11x0Interface.h"
|
||||||
|
#include "Module.h"
|
||||||
#include "platform/portduino/USBHal.h"
|
#include "platform/portduino/USBHal.h"
|
||||||
|
|
||||||
// Product strings for auto-configuration
|
// Product strings for auto-configuration
|
||||||
// {"PRODUCT_STRING", "CONFIG.YAML"}
|
// {"PRODUCT_STRING", "CONFIG.YAML"}
|
||||||
// YAML paths are relative to `meshtastic/available.d`
|
// YAML paths are relative to `meshtastic/available.d`
|
||||||
inline const std::unordered_map<std::string, std::string> configProducts = {{"MESHTOAD", "lora-usb-meshtoad-e22.yaml"},
|
inline const std::unordered_map<std::string, std::string> configProducts = {
|
||||||
{"MESHSTICK", "lora-meshstick-1262.yaml"},
|
{"MESHTOAD", "lora-usb-meshtoad-e22.yaml"},
|
||||||
{"MESHADV-PI", "lora-MeshAdv-900M30S.yaml"},
|
{"MESHSTICK", "lora-meshstick-1262.yaml"},
|
||||||
{"MeshAdv Mini", "lora-MeshAdv-Mini-900M22S.yaml"},
|
{"MESHADV-PI", "lora-MeshAdv-900M30S.yaml"},
|
||||||
{"POWERPI", "lora-MeshAdv-900M30S.yaml"}};
|
{"MeshAdv Mini", "lora-MeshAdv-Mini-900M22S.yaml"},
|
||||||
|
{"POWERPI", "lora-MeshAdv-900M30S.yaml"},
|
||||||
|
{"RAK6421-13300-S1", "lora-RAK6421-13300-slot1.yaml"},
|
||||||
|
{"RAK6421-13300-S2", "lora-RAK6421-13300-slot2.yaml"}};
|
||||||
|
|
||||||
enum configNames {
|
enum configNames {
|
||||||
default_gpiochip,
|
default_gpiochip,
|
||||||
@@ -127,3 +132,12 @@ static bool ends_with(std::string_view str, std::string_view suffix);
|
|||||||
void getMacAddr(uint8_t *dmac);
|
void getMacAddr(uint8_t *dmac);
|
||||||
bool MAC_from_string(std::string mac_str, uint8_t *dmac);
|
bool MAC_from_string(std::string mac_str, uint8_t *dmac);
|
||||||
std::string exec(const char *cmd);
|
std::string exec(const char *cmd);
|
||||||
|
|
||||||
|
extern struct portduino_config_struct {
|
||||||
|
bool has_rfswitch_table = false;
|
||||||
|
uint32_t rfswitch_dio_pins[5] = {RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
|
||||||
|
Module::RfSwitchMode_t rfswitch_table[8];
|
||||||
|
bool force_simradio = false;
|
||||||
|
bool has_device_id = false;
|
||||||
|
uint8_t device_id[16] = {0};
|
||||||
|
} portduino_config;
|
||||||
@@ -128,6 +128,8 @@ class Power : private concurrency::OSThread
|
|||||||
bool lipoInit();
|
bool lipoInit();
|
||||||
/// Setup a Lipo charger
|
/// Setup a Lipo charger
|
||||||
bool lipoChargerInit();
|
bool lipoChargerInit();
|
||||||
|
/// Setup a meshSolar battery sensor
|
||||||
|
bool meshSolarInit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ build_flags = ${esp32s3_base.build_flags} -Os
|
|||||||
-D MESHTASTIC_EXCLUDE_SERIAL=1
|
-D MESHTASTIC_EXCLUDE_SERIAL=1
|
||||||
-D MESHTASTIC_EXCLUDE_SOCKETAPI=1
|
-D MESHTASTIC_EXCLUDE_SOCKETAPI=1
|
||||||
-D MESHTASTIC_EXCLUDE_SCREEN=1
|
-D MESHTASTIC_EXCLUDE_SCREEN=1
|
||||||
-D MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR=1
|
|
||||||
-D HAS_TELEMETRY=0
|
|
||||||
-D CONFIG_DISABLE_HAL_LOCKS=1
|
-D CONFIG_DISABLE_HAL_LOCKS=1
|
||||||
-D USE_PIN_BUZZER
|
-D USE_PIN_BUZZER
|
||||||
-D HAS_SCREEN=0
|
-D HAS_SCREEN=0
|
||||||
|
|||||||
@@ -92,3 +92,12 @@
|
|||||||
#define SX126X_DIO3_TCXO_VOLTAGE 2.4
|
#define SX126X_DIO3_TCXO_VOLTAGE 2.4
|
||||||
// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
|
// Internally the TTGO module hooks the SX1262-DIO2 in to control the TX/RX switch (which is the default for the sx1262interface
|
||||||
// code)
|
// code)
|
||||||
|
|
||||||
|
#define MODEM_POWER_EN 41
|
||||||
|
#define MODEM_PWRKEY 40
|
||||||
|
#define MODEM_RST 9
|
||||||
|
#define MODEM_RI 7
|
||||||
|
#define MODEM_DTR 8
|
||||||
|
#define MODEM_RX 10
|
||||||
|
#define MODEM_TX 11
|
||||||
|
|
||||||
|
|||||||
19
variants/esp32s3/tlora-pager/pins_arduino.h
Normal file
19
variants/esp32s3/tlora-pager/pins_arduino.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef Pins_Arduino_h
|
||||||
|
#define Pins_Arduino_h
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define USB_VID 0x303a
|
||||||
|
#define USB_PID 0x1001
|
||||||
|
|
||||||
|
// used for keyboard, battery gauge, charger and haptic driver
|
||||||
|
static const uint8_t SDA = 3;
|
||||||
|
static const uint8_t SCL = 2;
|
||||||
|
|
||||||
|
// Default SPI will be mapped to Radio
|
||||||
|
static const uint8_t SS = 36;
|
||||||
|
static const uint8_t MOSI = 34;
|
||||||
|
static const uint8_t MISO = 33;
|
||||||
|
static const uint8_t SCK = 35;
|
||||||
|
|
||||||
|
#endif /* Pins_Arduino_h */
|
||||||
71
variants/esp32s3/tlora-pager/platformio.ini
Normal file
71
variants/esp32s3/tlora-pager/platformio.ini
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
; LilyGo T-Lora-Pager
|
||||||
|
[env:tlora-pager]
|
||||||
|
extends = esp32s3_base
|
||||||
|
board = t-deck-pro ; same as T-Deck Pro
|
||||||
|
board_check = true
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
|
upload_protocol = esptool
|
||||||
|
|
||||||
|
build_flags = ${esp32s3_base.build_flags}
|
||||||
|
-I variants/esp32s3/tlora-pager
|
||||||
|
-D T_LORA_PAGER
|
||||||
|
-D BOARD_HAS_PSRAM
|
||||||
|
-D GPS_POWER_TOGGLE
|
||||||
|
-D HAS_SDCARD
|
||||||
|
-D SDCARD_USE_SPI1
|
||||||
|
-D ENABLE_ROTARY_PULLUP
|
||||||
|
-D ENABLE_BUTTON_PULLUP
|
||||||
|
-D HALF_STEP
|
||||||
|
|
||||||
|
lib_deps = ${esp32s3_base.lib_deps}
|
||||||
|
lovyan03/LovyanGFX@1.2.7
|
||||||
|
earlephilhower/ESP8266Audio@1.9.9
|
||||||
|
earlephilhower/ESP8266SAM@1.0.1
|
||||||
|
adafruit/Adafruit DRV2605 Library@1.2.4
|
||||||
|
lewisxhe/PCF8563_Library@1.0.1
|
||||||
|
lewisxhe/SensorLib@0.3.1
|
||||||
|
https://github.com/pschatzmann/arduino-audio-driver/archive/refs/tags/v0.1.3.zip
|
||||||
|
https://github.com/mverch67/BQ27220/archive/07d92be846abd8a0258a50c23198dac0858b22ed.zip
|
||||||
|
https://github.com/mverch67/RotaryEncoder
|
||||||
|
|
||||||
|
[env:tlora-pager-tft]
|
||||||
|
board_level = extra
|
||||||
|
extends = env:tlora-pager
|
||||||
|
build_flags =
|
||||||
|
${env:tlora-pager.build_flags}
|
||||||
|
-D CONFIG_DISABLE_HAL_LOCKS=1
|
||||||
|
-D INPUTDRIVER_ROTARY_TYPE=1
|
||||||
|
-D INPUTDRIVER_ROTARY_UP=40
|
||||||
|
-D INPUTDRIVER_ROTARY_DOWN=41
|
||||||
|
-D INPUTDRIVER_ROTARY_BTN=7
|
||||||
|
-D INPUTDRIVER_BUTTON_TYPE=0
|
||||||
|
-D HAS_SCREEN=1
|
||||||
|
-D HAS_TFT=1
|
||||||
|
-D USE_I2S_BUZZER
|
||||||
|
-D RAM_SIZE=5120
|
||||||
|
-D LV_LVGL_H_INCLUDE_SIMPLE
|
||||||
|
-D LV_CONF_INCLUDE_SIMPLE
|
||||||
|
-D LV_COMP_CONF_INCLUDE_SIMPLE
|
||||||
|
-D LV_USE_SYSMON=0
|
||||||
|
-D LV_USE_PROFILER=0
|
||||||
|
-D LV_USE_PERF_MONITOR=0
|
||||||
|
-D LV_USE_MEM_MONITOR=0
|
||||||
|
-D LV_USE_LOG=0
|
||||||
|
-D USE_LOG_DEBUG
|
||||||
|
-D LOG_DEBUG_INC=\"DebugConfiguration.h\"
|
||||||
|
-D RADIOLIB_SPI_PARANOID=0
|
||||||
|
-D LGFX_SCREEN_WIDTH=222
|
||||||
|
-D LGFX_SCREEN_HEIGHT=480
|
||||||
|
-D DISPLAY_SIZE=480x222 ; landscape mode
|
||||||
|
-D DISPLAY_SET_RESOLUTION
|
||||||
|
-D LGFX_DRIVER=LGFX_TLORA_PAGER
|
||||||
|
-D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_T_LORA_PAGER.h\"
|
||||||
|
; -D LVGL_DRIVER=LVGL_T_LORA_PAGER
|
||||||
|
; -D LV_USE_ST7796=1
|
||||||
|
-D VIEW_480x222
|
||||||
|
-D USE_PACKET_API
|
||||||
|
-D MAP_FULL_REDRAW
|
||||||
|
|
||||||
|
lib_deps =
|
||||||
|
${env:tlora-pager.lib_deps}
|
||||||
|
${device-ui_base.lib_deps}
|
||||||
125
variants/esp32s3/tlora-pager/variant.h
Normal file
125
variants/esp32s3/tlora-pager/variant.h
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
// ST7796 TFT LCD
|
||||||
|
#define TFT_CS 38
|
||||||
|
#define ST7796_CS TFT_CS
|
||||||
|
#define ST7796_RS 37 // DC
|
||||||
|
#define ST7796_SDA MOSI // MOSI
|
||||||
|
#define ST7796_SCK SCK
|
||||||
|
#define ST7796_RESET -1
|
||||||
|
#define ST7796_MISO MISO
|
||||||
|
#define ST7796_BUSY -1
|
||||||
|
#define ST7796_BL 42
|
||||||
|
#define ST7796_SPI_HOST SPI2_HOST
|
||||||
|
#define TFT_BL 42
|
||||||
|
#define SPI_FREQUENCY 75000000
|
||||||
|
#define SPI_READ_FREQUENCY 16000000
|
||||||
|
#define TFT_HEIGHT 480
|
||||||
|
#define TFT_WIDTH 222
|
||||||
|
#define TFT_OFFSET_X 49
|
||||||
|
#define TFT_OFFSET_Y 0
|
||||||
|
#define TFT_OFFSET_ROTATION 3
|
||||||
|
#define SCREEN_ROTATE
|
||||||
|
#define SCREEN_TRANSITION_FRAMERATE 5
|
||||||
|
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
|
||||||
|
|
||||||
|
#define I2C_SDA SDA
|
||||||
|
#define I2C_SCL SCL
|
||||||
|
|
||||||
|
#define USE_POWERSAVE
|
||||||
|
#define SLEEP_TIME 120
|
||||||
|
|
||||||
|
// GNNS
|
||||||
|
#define HAS_GPS 1
|
||||||
|
#define GPS_BAUDRATE 38400
|
||||||
|
#define GPS_RX_PIN 4
|
||||||
|
#define GPS_TX_PIN 12
|
||||||
|
#define PIN_GPS_PPS 13
|
||||||
|
|
||||||
|
// PCF8563 RTC Module
|
||||||
|
#if __has_include("pcf8563.h")
|
||||||
|
#include "pcf8563.h"
|
||||||
|
#endif
|
||||||
|
#define PCF8563_RTC 0x51
|
||||||
|
#define HAS_RTC 1
|
||||||
|
|
||||||
|
// Rotary
|
||||||
|
#define ROTARY_A (40)
|
||||||
|
#define ROTARY_B (41)
|
||||||
|
#define ROTARY_PRESS (7)
|
||||||
|
|
||||||
|
#define BUTTON_PIN 0
|
||||||
|
|
||||||
|
// SPI interface SD card slot
|
||||||
|
#define SPI_MOSI MOSI
|
||||||
|
#define SPI_SCK SCK
|
||||||
|
#define SPI_MISO MISO
|
||||||
|
#define SPI_CS 21
|
||||||
|
#define SDCARD_CS SPI_CS
|
||||||
|
#define SD_SPI_FREQUENCY 75000000U
|
||||||
|
|
||||||
|
// TCA8418 keyboard
|
||||||
|
#define I2C_NO_RESCAN
|
||||||
|
#define KB_BL_PIN 46
|
||||||
|
#define KB_INT 6
|
||||||
|
#define CANNED_MESSAGE_MODULE_ENABLE 1
|
||||||
|
|
||||||
|
// audio codec ES8311
|
||||||
|
#define HAS_I2S
|
||||||
|
#define DAC_I2S_BCK 11
|
||||||
|
#define DAC_I2S_WS 18
|
||||||
|
#define DAC_I2S_DOUT 45
|
||||||
|
#define DAC_I2S_DIN 17
|
||||||
|
#define DAC_I2S_MCLK 10
|
||||||
|
|
||||||
|
// gyroscope BHI260AP
|
||||||
|
#define HAS_BHI260AP
|
||||||
|
|
||||||
|
// battery charger BQ25896
|
||||||
|
#define HAS_PPM 1
|
||||||
|
#define XPOWERS_CHIP_BQ25896
|
||||||
|
|
||||||
|
// battery quality management BQ27220
|
||||||
|
#define HAS_BQ27220 1
|
||||||
|
#define BQ27220_I2C_SDA SDA
|
||||||
|
#define BQ27220_I2C_SCL SCL
|
||||||
|
#define BQ27220_DESIGN_CAPACITY 1500
|
||||||
|
|
||||||
|
// NFC ST25R3916
|
||||||
|
#define NFC_INT 5
|
||||||
|
#define NFC_CS 39
|
||||||
|
|
||||||
|
// External expansion chip XL9555
|
||||||
|
#define USE_XL9555
|
||||||
|
#define EXPANDS_DRV_EN (0)
|
||||||
|
#define EXPANDS_AMP_EN (1)
|
||||||
|
#define EXPANDS_KB_RST (2)
|
||||||
|
#define EXPANDS_LORA_EN (3)
|
||||||
|
#define EXPANDS_GPS_EN (4)
|
||||||
|
#define EXPANDS_NFC_EN (5)
|
||||||
|
#define EXPANDS_GPS_RST (7)
|
||||||
|
#define EXPANDS_KB_EN (8)
|
||||||
|
#define EXPANDS_GPIO_EN (9)
|
||||||
|
#define EXPANDS_SD_DET (10)
|
||||||
|
#define EXPANDS_SD_PULLEN (11)
|
||||||
|
#define EXPANDS_SD_EN (12)
|
||||||
|
|
||||||
|
// LoRa
|
||||||
|
#define USE_SX1262
|
||||||
|
#define USE_SX1268
|
||||||
|
|
||||||
|
#define LORA_SCK 35
|
||||||
|
#define LORA_MISO 33
|
||||||
|
#define LORA_MOSI 34
|
||||||
|
#define LORA_CS 36
|
||||||
|
|
||||||
|
#define LORA_DIO0 -1 // a No connect on the SX1262 module
|
||||||
|
#define LORA_RESET 47
|
||||||
|
#define LORA_DIO1 14 // SX1262 IRQ
|
||||||
|
#define LORA_DIO2 48 // SX1262 BUSY
|
||||||
|
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||||
|
|
||||||
|
#define SX126X_CS LORA_CS
|
||||||
|
#define SX126X_DIO1 LORA_DIO1
|
||||||
|
#define SX126X_BUSY LORA_DIO2
|
||||||
|
#define SX126X_RESET LORA_RESET
|
||||||
|
#define SX126X_DIO2_AS_RF_SWITCH
|
||||||
|
#define SX126X_DIO3_TCXO_VOLTAGE 3.0
|
||||||
@@ -32,6 +32,7 @@ lib_deps = ${esp32s3_base.lib_deps}
|
|||||||
|
|
||||||
|
|
||||||
[env:unphone-tft]
|
[env:unphone-tft]
|
||||||
|
board_level = extra
|
||||||
extends = env:unphone
|
extends = env:unphone
|
||||||
build_flags =
|
build_flags =
|
||||||
${env:unphone.build_flags}
|
${env:unphone.build_flags}
|
||||||
@@ -52,8 +53,6 @@ build_flags =
|
|||||||
-D LV_USE_PERF_MONITOR=0
|
-D LV_USE_PERF_MONITOR=0
|
||||||
-D LV_USE_MEM_MONITOR=0
|
-D LV_USE_MEM_MONITOR=0
|
||||||
-D LV_USE_LOG=0
|
-D LV_USE_LOG=0
|
||||||
-D USE_LOG_DEBUG
|
|
||||||
-D LOG_DEBUG_INC=\"DebugConfiguration.h\"
|
|
||||||
-D LGFX_SCREEN_WIDTH=320
|
-D LGFX_SCREEN_WIDTH=320
|
||||||
-D LGFX_SCREEN_HEIGHT=480
|
-D LGFX_SCREEN_HEIGHT=480
|
||||||
-D DISPLAY_SIZE=320x480 ; portrait mode
|
-D DISPLAY_SIZE=320x480 ; portrait mode
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ build_flags = ${native_base.build_flags} -Os -lX11 -linput -lxkbcommon -ffunctio
|
|||||||
-D USE_X11=1
|
-D USE_X11=1
|
||||||
-D HAS_TFT=1
|
-D HAS_TFT=1
|
||||||
-D HAS_SCREEN=1
|
-D HAS_SCREEN=1
|
||||||
|
|
||||||
-D LV_CACHE_DEF_SIZE=6291456
|
-D LV_CACHE_DEF_SIZE=6291456
|
||||||
-D LV_BUILD_TEST=0
|
-D LV_BUILD_TEST=0
|
||||||
-D LV_USE_LIBINPUT=1
|
-D LV_USE_LIBINPUT=1
|
||||||
@@ -41,6 +40,25 @@ build_flags = ${native_base.build_flags} -Os -lX11 -linput -lxkbcommon -ffunctio
|
|||||||
build_src_filter =
|
build_src_filter =
|
||||||
${native_base.build_src_filter}
|
${native_base.build_src_filter}
|
||||||
|
|
||||||
|
[env:native-sdl]
|
||||||
|
extends = native_base
|
||||||
|
build_type = release
|
||||||
|
lib_deps =
|
||||||
|
${env.lib_deps}
|
||||||
|
${networking_base.lib_deps}
|
||||||
|
${radiolib_base.lib_deps}
|
||||||
|
${environmental_base.lib_deps}
|
||||||
|
# renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
|
||||||
|
rweather/Crypto@0.4.0
|
||||||
|
# renovate: datasource=git-refs depName=libch341-spi-userspace packageName=https://github.com/pine64/libch341-spi-userspace gitBranch=main
|
||||||
|
https://github.com/pine64/libch341-spi-userspace/archive/af9bc27c9c30fa90772279925b7c5913dff789b4.zip
|
||||||
|
# renovate: datasource=custom.pio depName=adafruit/Adafruit seesaw Library packageName=adafruit/library/Adafruit seesaw Library
|
||||||
|
adafruit/Adafruit seesaw Library@1.7.9
|
||||||
|
https://github.com/jp-bennett/LovyanGFX/archive/7458f84a126c1f8fdc7b038074f71be903f6e4c0.zip
|
||||||
|
build_flags = ${native_base.build_flags}
|
||||||
|
!pkg-config --cflags --libs sdl2 --silence-errors || :
|
||||||
|
-D LGFX_SDL=1
|
||||||
|
|
||||||
[env:native-fb]
|
[env:native-fb]
|
||||||
extends = native_base
|
extends = native_base
|
||||||
build_type = release
|
build_type = release
|
||||||
|
|||||||
19
variants/nrf52840/heltec_mesh_solar/platformio.ini
Normal file
19
variants/nrf52840/heltec_mesh_solar/platformio.ini
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
; First prototype nrf52840/sx1262 device
|
||||||
|
[env:heltec-mesh-solar]
|
||||||
|
extends = nrf52840_base
|
||||||
|
board = heltec_mesh_solar
|
||||||
|
board_level = pr
|
||||||
|
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/nrf52840/heltec_mesh_solar
|
||||||
|
-DGPS_POWER_TOGGLE
|
||||||
|
-DHELTEC_MESH_SOLAR
|
||||||
|
|
||||||
|
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/heltec_mesh_solar>
|
||||||
|
lib_deps =
|
||||||
|
${nrf52840_base.lib_deps}
|
||||||
|
https://github.com/NMIoT/meshsolar/archive/dfc5330dad443982e6cdd37a61d33fc7252f468b.zip
|
||||||
|
lewisxhe/PCF8563_Library@^1.0.1
|
||||||
|
ArduinoJson@6.21.4
|
||||||
36
variants/nrf52840/heltec_mesh_solar/variant.cpp
Normal file
36
variants/nrf52840/heltec_mesh_solar/variant.cpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||||
|
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||||
|
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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};
|
||||||
|
|
||||||
|
void initVariant()
|
||||||
|
{
|
||||||
|
pinMode(BQ4050_EMERGENCY_SHUTDOWN_PIN, INPUT);
|
||||||
|
}
|
||||||
157
variants/nrf52840/heltec_mesh_solar/variant.h
Normal file
157
variants/nrf52840/heltec_mesh_solar/variant.h
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||||
|
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||||
|
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
|
||||||
|
#define PIN_LED1 (0 + 12) // green (confirmed on 1.0 board)
|
||||||
|
#define LED_BLUE PIN_LED1 // fake for bluefruit library
|
||||||
|
#define LED_GREEN PIN_LED1
|
||||||
|
#define LED_BUILTIN LED_GREEN
|
||||||
|
#define LED_STATE_ON 0 // State when LED is lit
|
||||||
|
|
||||||
|
#define HAS_NEOPIXEL // Enable the use of neopixels
|
||||||
|
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
|
||||||
|
#define NEOPIXEL_DATA (32+15) // gpio pin used to send data to the neopixels
|
||||||
|
#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 + 9)
|
||||||
|
#define PIN_SERIAL2_TX (0 + 10)
|
||||||
|
// #define PIN_SERIAL2_EN (0 + 17)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I2C
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define WIRE_INTERFACES_COUNT 2
|
||||||
|
|
||||||
|
// I2C bus 0
|
||||||
|
// Routed to footprint for PCF8563TS RTC
|
||||||
|
// Not populated on T114 V1, maybe in future?
|
||||||
|
#define PIN_WIRE_SDA (0 + 6) // P0.26
|
||||||
|
#define PIN_WIRE_SCL (0 + 26) // P0.26
|
||||||
|
|
||||||
|
// I2C bus 1
|
||||||
|
// Available on header pins, for general use
|
||||||
|
#define PIN_WIRE1_SDA (0 + 30) // P0.30
|
||||||
|
#define PIN_WIRE1_SCL (0 + 5) // P0.13
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lora radio
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define USE_SX1262
|
||||||
|
// #define USE_SX1268
|
||||||
|
#define SX126X_CS (0 + 24) // FIXME - we really should define LORA_CS instead
|
||||||
|
#define LORA_CS (0 + 24)
|
||||||
|
#define SX126X_DIO1 (0 + 20)
|
||||||
|
// 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 + 17)
|
||||||
|
#define SX126X_RESET (0 + 25)
|
||||||
|
// 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPS pins
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GPS_L76K
|
||||||
|
|
||||||
|
// #define PIN_GPS_RESET (32 + 6) // An output to reset L76K GPS. As per datasheet, low for > 100ms will reset the L76K
|
||||||
|
// #define GPS_RESET_MODE LOW
|
||||||
|
// #define PIN_GPS_EN (21)
|
||||||
|
#define PERIPHERAL_WARMUP_MS 1000 // Make sure I2C QuickLink has stable power before continuing
|
||||||
|
#define VEXT_ON_VALUE HIGH
|
||||||
|
// #define GPS_EN_ACTIVE HIGH
|
||||||
|
#define PIN_GPS_STANDBY (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake
|
||||||
|
#define PIN_GPS_PPS (32 + 4)
|
||||||
|
// Seems to be missing on this new board
|
||||||
|
// #define PIN_GPS_PPS (32 + 4) // Pulse per second input from the GPS
|
||||||
|
#define GPS_TX_PIN (32 + 5) // This is for bits going TOWARDS the CPU
|
||||||
|
#define GPS_RX_PIN (32 + 7) // This is for bits going TOWARDS the GPS
|
||||||
|
|
||||||
|
#define GPS_THREAD_INTERVAL 50
|
||||||
|
|
||||||
|
#define PIN_SERIAL1_RX GPS_TX_PIN
|
||||||
|
#define PIN_SERIAL1_TX GPS_RX_PIN
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPI Interfaces
|
||||||
|
*/
|
||||||
|
#define SPI_INTERFACES_COUNT 1
|
||||||
|
|
||||||
|
// For LORA, spi 0
|
||||||
|
#define PIN_SPI_MISO (0 + 23)
|
||||||
|
#define PIN_SPI_MOSI (0 + 22)
|
||||||
|
#define PIN_SPI_SCK (0 + 19)
|
||||||
|
|
||||||
|
// #define PIN_PWR_EN (0 + 6)
|
||||||
|
|
||||||
|
// To debug via the segger JLINK console rather than the CDC-ACM serial device
|
||||||
|
// #define USE_SEGGER
|
||||||
|
|
||||||
|
#define BQ4050_SDA_PIN (32+1) // I2C data line pin
|
||||||
|
#define BQ4050_SCL_PIN (32+0) // I2C clock line pin
|
||||||
|
#define BQ4050_EMERGENCY_SHUTDOWN_PIN (32+3) // Emergency shutdown pin
|
||||||
|
|
||||||
|
#define HAS_RTC 0
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
* Arduino objects - C++ only
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif
|
||||||
19
variants/nrf52840/meshtiny/platformio.ini
Normal file
19
variants/nrf52840/meshtiny/platformio.ini
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
; MeshTiny - Custom device based on GAT562 with encoder and buzzer support
|
||||||
|
[env:meshtiny]
|
||||||
|
extends = nrf52840_base
|
||||||
|
board = meshtiny
|
||||||
|
board_level = extra
|
||||||
|
build_flags = ${nrf52840_base.build_flags} -Ivariants/nrf52840/meshtiny -D MESHTINY
|
||||||
|
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
|
||||||
|
-DRADIOLIB_EXCLUDE_SX128X=1
|
||||||
|
-DRADIOLIB_EXCLUDE_SX127X=1
|
||||||
|
-DRADIOLIB_EXCLUDE_LR11X0=1
|
||||||
|
-D INPUTDRIVER_ENCODER_TYPE=2
|
||||||
|
-D INPUTDRIVER_ENCODER_UP=4
|
||||||
|
-D INPUTDRIVER_ENCODER_DOWN=26
|
||||||
|
-D INPUTDRIVER_ENCODER_BTN=28
|
||||||
|
-D USE_PIN_BUZZER=PIN_BUZZER
|
||||||
|
-D MESHTASTIC_EXCLUDE_GPS=1
|
||||||
|
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/meshtiny>
|
||||||
|
lib_deps =
|
||||||
|
${nrf52840_base.lib_deps}
|
||||||
54
variants/nrf52840/meshtiny/variant.cpp
Normal file
54
variants/nrf52840/meshtiny/variant.cpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||||
|
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||||
|
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "variant.h"
|
||||||
|
#include "nrf.h"
|
||||||
|
#include "wiring_constants.h"
|
||||||
|
#include "wiring_digital.h"
|
||||||
|
|
||||||
|
const uint32_t g_ADigitalPinMap[] = {
|
||||||
|
// P0
|
||||||
|
0, 1, 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};
|
||||||
|
|
||||||
|
void initVariant()
|
||||||
|
{
|
||||||
|
// LED1 & LED2
|
||||||
|
pinMode(PIN_LED1, OUTPUT);
|
||||||
|
ledOff(PIN_LED1);
|
||||||
|
|
||||||
|
pinMode(PIN_LED2, OUTPUT);
|
||||||
|
ledOff(PIN_LED2);
|
||||||
|
|
||||||
|
// 3V3 Power Rail
|
||||||
|
pinMode(PIN_3V3_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_3V3_EN, HIGH);
|
||||||
|
|
||||||
|
// Initialize Encoder pins
|
||||||
|
pinMode(INPUTDRIVER_ENCODER_UP, INPUT_PULLUP);
|
||||||
|
pinMode(INPUTDRIVER_ENCODER_DOWN, INPUT_PULLUP);
|
||||||
|
pinMode(INPUTDRIVER_ENCODER_BTN, INPUT_PULLUP);
|
||||||
|
|
||||||
|
// Initialize Buzzer pin
|
||||||
|
pinMode(PIN_BUZZER, OUTPUT);
|
||||||
|
digitalWrite(PIN_BUZZER, LOW);
|
||||||
|
}
|
||||||
199
variants/nrf52840/meshtiny/variant.h
Normal file
199
variants/nrf52840/meshtiny/variant.h
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||||
|
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||||
|
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _VARIANT_MESHTINY_
|
||||||
|
#define _VARIANT_MESHTINY_
|
||||||
|
|
||||||
|
#define MESHTINY
|
||||||
|
|
||||||
|
// #define RAK4630
|
||||||
|
|
||||||
|
/** Master clock frequency */
|
||||||
|
#define VARIANT_MCK (64000000ul)
|
||||||
|
|
||||||
|
#define USE_LFXO // Board uses 32khz crystal for LF
|
||||||
|
// define USE_LFRC // Board uses RC 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 (6)
|
||||||
|
#define NUM_ANALOG_OUTPUTS (0)
|
||||||
|
|
||||||
|
// LEDs
|
||||||
|
#define PIN_LED1 (35)
|
||||||
|
#define PIN_LED2 (36)
|
||||||
|
|
||||||
|
#define LED_BUILTIN PIN_LED1
|
||||||
|
#define LED_CONN PIN_LED2
|
||||||
|
|
||||||
|
#define LED_GREEN PIN_LED1
|
||||||
|
#define LED_BLUE PIN_LED2
|
||||||
|
|
||||||
|
#define LED_STATE_ON 1 // State when LED is litted
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encoder
|
||||||
|
*/
|
||||||
|
#define INPUTDRIVER_ENCODER_TYPE 2
|
||||||
|
#define INPUTDRIVER_ENCODER_UP 26
|
||||||
|
#define INPUTDRIVER_ENCODER_DOWN 4
|
||||||
|
#define INPUTDRIVER_ENCODER_BTN 28
|
||||||
|
|
||||||
|
#define CANNED_MESSAGE_MODULE_ENABLE 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Buzzer - PWM
|
||||||
|
*/
|
||||||
|
#define PIN_BUZZER 30
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Buttons
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PIN_BUTTON1 9
|
||||||
|
#define BUTTON_NEED_PULLUP
|
||||||
|
#define PIN_BUTTON2 12
|
||||||
|
#define PIN_BUTTON3 24
|
||||||
|
#define PIN_BUTTON4 25
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Analog pins
|
||||||
|
*/
|
||||||
|
#define PIN_A0 (5)
|
||||||
|
#define PIN_A1 (31)
|
||||||
|
#define PIN_A2 (28)
|
||||||
|
#define PIN_A3 (29)
|
||||||
|
#define PIN_A4 (30)
|
||||||
|
#define PIN_A5 (31)
|
||||||
|
#define PIN_A6 (0xff)
|
||||||
|
#define PIN_A7 (0xff)
|
||||||
|
|
||||||
|
static const uint8_t A0 = PIN_A0;
|
||||||
|
static const uint8_t A1 = PIN_A1;
|
||||||
|
static const uint8_t A2 = PIN_A2;
|
||||||
|
static const uint8_t A3 = PIN_A3;
|
||||||
|
static const uint8_t A4 = PIN_A4;
|
||||||
|
static const uint8_t A5 = PIN_A5;
|
||||||
|
static const uint8_t A6 = PIN_A6;
|
||||||
|
static const uint8_t A7 = PIN_A7;
|
||||||
|
#define ADC_RESOLUTION 14
|
||||||
|
|
||||||
|
// Other pins
|
||||||
|
#define PIN_AREF (2)
|
||||||
|
#define PIN_NFC1 (9)
|
||||||
|
#define PIN_NFC2 (10)
|
||||||
|
|
||||||
|
static const uint8_t AREF = PIN_AREF;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serial interfaces
|
||||||
|
*/
|
||||||
|
#define PIN_SERIAL1_RX (15)
|
||||||
|
#define PIN_SERIAL1_TX (16)
|
||||||
|
|
||||||
|
// Connected to Jlink CDC
|
||||||
|
#define PIN_SERIAL2_RX (8)
|
||||||
|
#define PIN_SERIAL2_TX (6)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPI Interfaces
|
||||||
|
*/
|
||||||
|
#define SPI_INTERFACES_COUNT 2
|
||||||
|
|
||||||
|
#define PIN_SPI_MISO (45)
|
||||||
|
#define PIN_SPI_MOSI (44)
|
||||||
|
#define PIN_SPI_SCK (43)
|
||||||
|
|
||||||
|
#define PIN_SPI1_MISO (29) // (0 + 29)
|
||||||
|
#define PIN_SPI1_MOSI (30) // (0 + 30)
|
||||||
|
#define PIN_SPI1_SCK (3) // (0 + 3)
|
||||||
|
|
||||||
|
static const uint8_t SS = 42;
|
||||||
|
static const uint8_t MOSI = PIN_SPI_MOSI;
|
||||||
|
static const uint8_t MISO = PIN_SPI_MISO;
|
||||||
|
static const uint8_t SCK = PIN_SPI_SCK;
|
||||||
|
|
||||||
|
#define HAS_SCREEN 1
|
||||||
|
#define USE_SSD1306
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wire Interfaces
|
||||||
|
*/
|
||||||
|
#define WIRE_INTERFACES_COUNT 1
|
||||||
|
|
||||||
|
#define PIN_WIRE_SDA (13)
|
||||||
|
#define PIN_WIRE_SCL (14)
|
||||||
|
|
||||||
|
// QSPI Pins
|
||||||
|
#define PIN_QSPI_SCK 3
|
||||||
|
#define PIN_QSPI_CS 22 // Changed from 26 to avoid conflict with encoder
|
||||||
|
#define PIN_QSPI_IO0 27 // Changed from 30 to avoid conflict with buzzer
|
||||||
|
#define PIN_QSPI_IO1 29
|
||||||
|
#define PIN_QSPI_IO2 21 // Changed from 28 to avoid conflict with encoder button
|
||||||
|
#define PIN_QSPI_IO3 2
|
||||||
|
|
||||||
|
// On-board QSPI Flash
|
||||||
|
#define EXTERNAL_FLASH_DEVICES IS25LP080D
|
||||||
|
#define EXTERNAL_FLASH_USE_QSPI
|
||||||
|
|
||||||
|
#define USE_SX1262
|
||||||
|
#define SX126X_CS (42)
|
||||||
|
#define SX126X_DIO1 (47)
|
||||||
|
#define SX126X_BUSY (46)
|
||||||
|
#define SX126X_RESET (38)
|
||||||
|
#define SX126X_POWER_EN (37)
|
||||||
|
// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3
|
||||||
|
#define SX126X_DIO2_AS_RF_SWITCH
|
||||||
|
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||||
|
|
||||||
|
// Testing USB detection
|
||||||
|
#define NRF_APM
|
||||||
|
|
||||||
|
#define PIN_3V3_EN (34)
|
||||||
|
|
||||||
|
// Battery
|
||||||
|
// The battery sense is hooked to pin A0 (5)
|
||||||
|
#define BATTERY_PIN PIN_A0
|
||||||
|
// and has 12 bit resolution
|
||||||
|
#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 1.73
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
* Arduino objects - C++ only
|
||||||
|
*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -18,16 +18,9 @@
|
|||||||
|
|
||||||
// Shared NicheGraphics components
|
// Shared NicheGraphics components
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
#include "graphics/niche/Drivers/Backlight/LatchingBacklight.h"
|
#include "graphics/niche/Drivers/EInk/ZJY122250_0213BAAMFGN.h"
|
||||||
#include "graphics/niche/Drivers/EInk/GDEY0213B74.h"
|
|
||||||
#include "graphics/niche/Inputs/TwoButton.h"
|
#include "graphics/niche/Inputs/TwoButton.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;
|
||||||
@@ -41,7 +34,7 @@ void setupNicheGraphics()
|
|||||||
// E-Ink Driver
|
// E-Ink Driver
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
|
|
||||||
Drivers::EInk *driver = new Drivers::GDEY0213B74;
|
Drivers::EInk *driver = new Drivers::ZJY122250_0213BAAMFGN;
|
||||||
driver->begin(&SPI1, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES);
|
driver->begin(&SPI1, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES);
|
||||||
|
|
||||||
// InkHUD
|
// InkHUD
|
||||||
@@ -53,8 +46,7 @@ void setupNicheGraphics()
|
|||||||
inkhud->setDriver(driver);
|
inkhud->setDriver(driver);
|
||||||
|
|
||||||
// Set how many FAST updates per FULL update
|
// Set how many FAST updates per FULL update
|
||||||
// Set how unhealthy additional FAST updates beyond this number are
|
inkhud->setDisplayResilience(15);
|
||||||
inkhud->setDisplayResilience(7, 1.5);
|
|
||||||
|
|
||||||
// Select fonts
|
// Select fonts
|
||||||
InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252;
|
InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252;
|
||||||
@@ -62,16 +54,10 @@ void setupNicheGraphics()
|
|||||||
InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252;
|
InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252;
|
||||||
|
|
||||||
// Customize default settings
|
// Customize default settings
|
||||||
inkhud->persistence->settings.userTiles.maxCount = 2; // Two applets side-by-side
|
inkhud->persistence->settings.rotation = 1; // 90 degrees clockwise
|
||||||
// 270 degrees clockwise
|
|
||||||
inkhud->persistence->settings.optionalFeatures.batteryIcon = true; // Device definitely has a battery
|
inkhud->persistence->settings.optionalFeatures.batteryIcon = true; // Device definitely has a battery
|
||||||
inkhud->persistence->settings.optionalMenuItems.backlight = true; // Until proves capacitive button works by touching it
|
inkhud->persistence->settings.userTiles.count = 1; // One tile only by default, keep things simple for new users
|
||||||
inkhud->persistence->settings.userTiles.count = 1; // One tile only by default, keep things simple for new users
|
inkhud->persistence->settings.userTiles.maxCount = 2; // Two applets side-by-side
|
||||||
|
|
||||||
// Setup backlight controller
|
|
||||||
// Note: AUX button attached further down
|
|
||||||
Drivers::LatchingBacklight *backlight = Drivers::LatchingBacklight::getInstance();
|
|
||||||
backlight->setPin(PIN_EINK_EN);
|
|
||||||
|
|
||||||
// Pick applets
|
// Pick applets
|
||||||
// Note: order of applets determines priority of "auto-show" feature
|
// Note: order of applets determines priority of "auto-show" feature
|
||||||
@@ -83,11 +69,9 @@ void setupNicheGraphics()
|
|||||||
inkhud->addApplet("Recents List", new InkHUD::RecentsListApplet); // -
|
inkhud->addApplet("Recents List", new InkHUD::RecentsListApplet); // -
|
||||||
inkhud->addApplet("Heard", new InkHUD::HeardApplet, true, false, 0); // Activated, no autoshow, default on tile 0
|
inkhud->addApplet("Heard", new InkHUD::HeardApplet, true, false, 0); // Activated, no autoshow, default on tile 0
|
||||||
|
|
||||||
inkhud->persistence->settings.rotation = 1;
|
|
||||||
// inkhud->persistence->printSettings(&inkhud->persistence->settings);
|
|
||||||
// Start running InkHUD
|
// Start running InkHUD
|
||||||
inkhud->begin();
|
inkhud->begin();
|
||||||
// inkhud->persistence->printSettings(&inkhud->persistence->settings);
|
|
||||||
// Buttons
|
// Buttons
|
||||||
// --------------------------
|
// --------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,47 @@
|
|||||||
[env:seeed_wio_tracker_L1_eink]
|
[env:seeed_wio_tracker_L1_eink]
|
||||||
board = seeed_wio_tracker_L1
|
board = seeed_wio_tracker_L1
|
||||||
extends = nrf52840_base, inkhud
|
extends = nrf52840_base
|
||||||
;board_level = extra
|
;board_level = extra
|
||||||
build_flags = ${nrf52840_base.build_flags}
|
build_flags = ${nrf52840_base.build_flags}
|
||||||
${inkhud.build_flags}
|
|
||||||
-I variants/nrf52840/seeed_wio_tracker_L1_eink
|
-I variants/nrf52840/seeed_wio_tracker_L1_eink
|
||||||
-D SEEED_WIO_TRACKER_L1_EINK
|
-D SEEED_WIO_TRACKER_L1_EINK
|
||||||
-D SEEED_WIO_TRACKER_L1
|
-D SEEED_WIO_TRACKER_L1
|
||||||
-I src/platform/nrf52/softdevice
|
-I src/platform/nrf52/softdevice
|
||||||
-I src/platform/nrf52/softdevice/nrf52
|
-I src/platform/nrf52/softdevice/nrf52
|
||||||
|
-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
|
||||||
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/nrf52840/seeed_wio_tracker_L1_eink> ${inkhud.build_src_filter}
|
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/seeed_wio_tracker_L1_eink>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${inkhud.lib_deps}
|
${nrf52840_base.lib_deps}
|
||||||
|
https://github.com/meshtastic/GxEPD2#b202ebfec6a4821e098cf7a625ba0f6f2400292d
|
||||||
|
debug_tool = jlink
|
||||||
|
|
||||||
|
[env:seeed_wio_tracker_L1_eink-inkhud]
|
||||||
|
board = seeed_wio_tracker_L1
|
||||||
|
extends = nrf52840_base, inkhud
|
||||||
|
build_flags =
|
||||||
|
${nrf52840_base.build_flags}
|
||||||
|
${inkhud.build_flags}
|
||||||
|
-I variants/nrf52840/seeed_wio_tracker_L1_eink
|
||||||
|
-D SEEED_WIO_TRACKER_L1
|
||||||
|
-D BUTTON_PIN=D13
|
||||||
|
board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld
|
||||||
|
build_src_filter =
|
||||||
|
${nrf52_base.build_src_filter}
|
||||||
|
${inkhud.build_src_filter}
|
||||||
|
+<../variants/nrf52840/seeed_wio_tracker_L1_eink>
|
||||||
|
lib_deps =
|
||||||
|
${inkhud.lib_deps} ; Before base libs_deps, so we use ZinggJM/GFXRoot instead of AdafruitGFX (saves space)
|
||||||
${nrf52840_base.lib_deps}
|
${nrf52840_base.lib_deps}
|
||||||
debug_tool = jlink
|
debug_tool = jlink
|
||||||
@@ -33,17 +33,10 @@
|
|||||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
// Button Configuration
|
// Button Configuration
|
||||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
#define CANCEL_BUTTON_PIN D13 // This is the Program Button
|
||||||
#ifdef BUTTON_PIN
|
|
||||||
#undef BUTTON_PIN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BUTTON_PIN D13 // This is the Program Button
|
|
||||||
// #define BUTTON_NEED_PULLUP 1
|
// #define BUTTON_NEED_PULLUP 1
|
||||||
#define BUTTON_ACTIVE_LOW true
|
#define CANCEL_BUTTON_ACTIVE_LOW true
|
||||||
#define BUTTON_ACTIVE_PULLUP false
|
#define CANCEL_BUTTON_ACTIVE_PULLUP false
|
||||||
|
|
||||||
#define BUTTON_PIN_TOUCH 13 // Touch button
|
|
||||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
// Digital Pin Mapping (D0-D10)
|
// Digital Pin Mapping (D0-D10)
|
||||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
@@ -116,7 +109,7 @@ static const uint8_t SCL = PIN_WIRE_SCL;
|
|||||||
#define PIN_EINK_SCLK 31
|
#define PIN_EINK_SCLK 31
|
||||||
#define PIN_EINK_MOSI 33
|
#define PIN_EINK_MOSI 33
|
||||||
#define PIN_EINK_EN 14 // unused
|
#define PIN_EINK_EN 14 // unused
|
||||||
#define PIN_SPI1_MISO 15 // unused
|
#define PIN_SPI1_MISO -1 // 15 unused
|
||||||
#define PIN_SPI1_MOSI PIN_EINK_MOSI
|
#define PIN_SPI1_MOSI PIN_EINK_MOSI
|
||||||
#define PIN_SPI1_SCK PIN_EINK_SCLK
|
#define PIN_SPI1_SCK PIN_EINK_SCLK
|
||||||
|
|
||||||
@@ -175,7 +168,17 @@ static const uint8_t SCL = PIN_WIRE_SCL;
|
|||||||
// joystick
|
// joystick
|
||||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
|
|
||||||
|
// trackball
|
||||||
|
#define HAS_TRACKBALL 1
|
||||||
|
#define TB_UP 25
|
||||||
|
#define TB_DOWN 26
|
||||||
|
#define TB_LEFT 27
|
||||||
|
#define TB_RIGHT 28
|
||||||
|
#define TB_PRESS 29
|
||||||
|
#define TB_DIRECTION FALLING
|
||||||
|
|
||||||
#define CANNED_MESSAGE_MODULE_ENABLE 1
|
#define CANNED_MESSAGE_MODULE_ENABLE 1
|
||||||
|
#define CANNED_MESSAGE_ADD_CONFIRMATION 1
|
||||||
|
|
||||||
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||||
// Compatibility Definitions
|
// Compatibility Definitions
|
||||||
|
|||||||
Reference in New Issue
Block a user