kopia lustrzana https://github.com/meshtastic/firmware
commit
2418fee444
|
@ -24,12 +24,13 @@ runs:
|
|||
python -m pip install --upgrade pip
|
||||
pip install -U platformio meshtastic adafruit-nrfutil
|
||||
|
||||
- name: Cache platformio
|
||||
uses: actions/cache@v1
|
||||
id: cache-platformio # needed in if test
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-platformio
|
||||
# Don't cache for now because I want to be lazy with portuino updates githashes
|
||||
# - name: Cache platformio
|
||||
# uses: actions/cache@v1
|
||||
# id: cache-platformio # needed in if test
|
||||
# with:
|
||||
# path: ~/.platformio
|
||||
# key: ${{ runner.os }}-platformio
|
||||
|
||||
- name: Upgrade platformio
|
||||
run: |
|
||||
|
|
|
@ -9,6 +9,8 @@ main/credentials.h
|
|||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
.idea/workspace.xml
|
||||
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
.autotools
|
||||
|
@ -20,3 +22,4 @@ nanopb*
|
|||
flash.uf2
|
||||
cmake-build*
|
||||
__pycache__
|
||||
|
||||
|
|
|
@ -1,178 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeRunConfigurationManager" shouldGenerate="true" shouldDeleteObsolete="true">
|
||||
<generated>
|
||||
<config projectName="meshtastic-esp32" targetName="Debug" />
|
||||
<config projectName="meshtastic-esp32" targetName="Production" />
|
||||
<config projectName="meshtastic-esp32" targetName="Z_DUMMY_TARGET" />
|
||||
</generated>
|
||||
</component>
|
||||
<component name="CMakeSettings">
|
||||
<configurations>
|
||||
<configuration PROFILE_NAME="native" CONFIG_NAME="native" ENABLED="true" />
|
||||
</configurations>
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="58922733-b05b-4b90-9655-b9b18914977a" name="Default Changelist" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/geeksville-private/pine64.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.vscode/settings.json" beforeDir="false" afterPath="$PROJECT_DIR$/.vscode/settings.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/geeksville-private/TODO.md" beforeDir="false" afterPath="$PROJECT_DIR$/geeksville-private/TODO.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/platformio.ini" beforeDir="false" afterPath="$PROJECT_DIR$/platformio.ini" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/configuration.h" beforeDir="false" afterPath="$PROJECT_DIR$/src/configuration.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main.cpp" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.cpp" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/mesh/RF95Interface.h" beforeDir="false" afterPath="$PROJECT_DIR$/src/mesh/RF95Interface.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/mesh/RadioInterface.h" beforeDir="false" afterPath="$PROJECT_DIR$/src/mesh/RadioInterface.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/mesh/SX1262Interface.h" beforeDir="false" afterPath="$PROJECT_DIR$/src/mesh/SX1262Interface.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/portduino/PortduinoGlue.cpp" beforeDir="false" afterPath="$PROJECT_DIR$/src/portduino/PortduinoGlue.cpp" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectId" id="1pmWHw2wau2TbdKvXvmQUB0EUE9" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="ASKED_ADD_EXTERNAL_FILES" value="true" />
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="cf.advertisement.text.overridden" value="true" />
|
||||
<property name="cf.first.check.clang-format" value="false" />
|
||||
<property name="node.js.detected.package.eslint" value="true" />
|
||||
<property name="node.js.detected.package.tslint" value="true" />
|
||||
<property name="node.js.path.for.package.eslint" value="project" />
|
||||
<property name="node.js.path.for.package.tslint" value="project" />
|
||||
<property name="node.js.selected.package.eslint" value="(autodetect)" />
|
||||
<property name="node.js.selected.package.tslint" value="(autodetect)" />
|
||||
<property name="settings.editor.selected.configurable" value="CMakeSettings" />
|
||||
</component>
|
||||
<component name="RunManager" selected="GDB Remote Debug.gdbremote-localhost-2345">
|
||||
<configuration default="true" type="CLion_Remote" version="1" remoteCommand="tcp:localhost:2345" symbolFile="" sysroot="">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="gdbremote-localhost-2345" type="CLion_Remote" version="1" remoteCommand="tcp:localhost:2345" symbolFile="" sysroot="">
|
||||
<debugger kind="GDB" isBundled="true" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="Z_DUMMY_TARGET" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="meshtastic-esp32" TARGET_NAME="Z_DUMMY_TARGET" CONFIG_NAME="native" RUN_TARGET_PROJECT_NAME="meshtastic-esp32" RUN_TARGET_NAME="Z_DUMMY_TARGET">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="PlatformIO Debug" type="platformio" factoryName="PlatformIO Debug" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="meshtastic-esp32" TARGET_NAME="Debug" CONFIG_NAME="native" RUN_TARGET_PROJECT_NAME="meshtastic-esp32" RUN_TARGET_NAME="Debug">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="PlatformIO Upload" type="platformio" factoryName="PlatformIO Upload" REDIRECT_INPUT="false" ELEVATE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="meshtastic-esp32" TARGET_NAME="Production" CONFIG_NAME="native" RUN_TARGET_PROJECT_NAME="meshtastic-esp32" RUN_TARGET_NAME="Production">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<list>
|
||||
<item itemvalue="CMake Application.Z_DUMMY_TARGET" />
|
||||
<item itemvalue="GDB Remote Debug.gdbremote-localhost-2345" />
|
||||
<item itemvalue="PlatformIO.PlatformIO Debug" />
|
||||
<item itemvalue="PlatformIO.PlatformIO Upload" />
|
||||
</list>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="58922733-b05b-4b90-9655-b9b18914977a" name="Default Changelist" comment="" />
|
||||
<created>1615788661896</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1615788661896</updated>
|
||||
<workItem from="1615788663210" duration="6661000" />
|
||||
<workItem from="1615938346019" duration="1208000" />
|
||||
<workItem from="1615971126983" duration="5945000" />
|
||||
<workItem from="1617115374907" duration="357000" />
|
||||
<workItem from="1617115747078" duration="1391000" />
|
||||
<workItem from="1617117632667" duration="307000" />
|
||||
<workItem from="1617160691713" duration="1016000" />
|
||||
<workItem from="1617279002260" duration="1626000" />
|
||||
<workItem from="1617425689081" duration="1896000" />
|
||||
<workItem from="1617437366919" duration="1182000" />
|
||||
<workItem from="1618544034975" duration="1185000" />
|
||||
<workItem from="1618624455224" duration="860000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State />
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="oldMeFiltersMigrated" value="true" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<breakpoints>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/src/mesh/wifi/WiFiServerAPI.cpp</url>
|
||||
<line>53</line>
|
||||
<option name="timeStamp" value="6" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/src/mesh/wifi/WiFiServerAPI.cpp</url>
|
||||
<line>37</line>
|
||||
<option name="timeStamp" value="7" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/src/mqtt/MQTT.cpp</url>
|
||||
<line>166</line>
|
||||
<option name="timeStamp" value="10" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/.pio/libdeps/native/PubSubClient/src/PubSubClient.cpp</url>
|
||||
<line>468</line>
|
||||
<option name="timeStamp" value="11" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$PROJECT_DIR$/src/mesh/mesh-pb-constants.cpp</url>
|
||||
<line>20</line>
|
||||
<option name="timeStamp" value="12" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
||||
<url>file://$USER_HOME$/.platformio/packages/framework-portduino/cores/portduino/PortduinoGPIO.cpp</url>
|
||||
<line>41</line>
|
||||
<option name="timeStamp" value="13" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
<watches-manager>
|
||||
<configuration name="CLion_Remote">
|
||||
<watch expression="radioConfig" language="ObjectiveC" />
|
||||
<watch expression="fromRadioScratch" language="ObjectiveC" />
|
||||
</configuration>
|
||||
</watches-manager>
|
||||
</component>
|
||||
<component name="XSLT-Support.FileAssociations.UIState">
|
||||
<expand />
|
||||
<select />
|
||||
</component>
|
||||
</project>
|
|
@ -8,7 +8,7 @@ BOARDS_ESP32="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec tbeam0.7"
|
|||
#BOARDS_ESP32=tbeam
|
||||
|
||||
# FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine
|
||||
BOARDS_NRF52="rak4631"
|
||||
BOARDS_NRF52="rak4631 t-echo"
|
||||
|
||||
OUTDIR=release/latest
|
||||
|
||||
|
|
|
@ -3,5 +3,5 @@ import configparser
|
|||
from readprops import readProps
|
||||
|
||||
|
||||
verStr = readProps('version.properties')
|
||||
print(f"{verStr}")
|
||||
verObj = readProps('version.properties')
|
||||
print(f"{verObj['long']}")
|
||||
|
|
|
@ -9,11 +9,12 @@ from readprops import readProps
|
|||
Import("projenv")
|
||||
|
||||
prefsLoc = projenv["PROJECT_DIR"] + "/version.properties"
|
||||
verStr = readProps(prefsLoc)
|
||||
print("Using meshtastic platform-custom.py, firmare version " + verStr)
|
||||
verObj = readProps(prefsLoc)
|
||||
print("Using meshtastic platform-custom.py, firmare version " + verObj['long'])
|
||||
# print("path is" + ','.join(sys.path))
|
||||
|
||||
# General options that are passed to the C and C++ compilers
|
||||
projenv.Append(CCFLAGS=[
|
||||
"-DAPP_VERSION=" + verStr
|
||||
"-DAPP_VERSION=" + verObj['long'],
|
||||
"-DAPP_VERSION_SHORT=" + verObj['short']
|
||||
])
|
||||
|
|
|
@ -12,6 +12,8 @@ def readProps(prefsLoc):
|
|||
config = configparser.RawConfigParser()
|
||||
config.read(prefsLoc)
|
||||
version = dict(config.items('VERSION'))
|
||||
verObj = dict(short = "{}.{}.{}".format(version["major"], version["minor"], version["build"]),
|
||||
long = "unset")
|
||||
|
||||
# Try to find current build SHA if if the workspace is clean. This could fail if git is not installed
|
||||
try:
|
||||
|
@ -23,14 +25,13 @@ def readProps(prefsLoc):
|
|||
if isDirty:
|
||||
# short for 'dirty', we want to keep our verstrings source for protobuf reasons
|
||||
suffix = sha + "-d"
|
||||
verStr = "{}.{}.{}.{}".format(
|
||||
verObj['long'] = "{}.{}.{}.{}".format(
|
||||
version["major"], version["minor"], version["build"], suffix)
|
||||
except:
|
||||
# print("Unexpected error:", sys.exc_info()[0])
|
||||
# traceback.print_exc()
|
||||
verStr = "{}.{}.{}".format(
|
||||
version["major"], version["minor"], version["build"])
|
||||
verObj['long'] = verObj['short']
|
||||
|
||||
# print("firmare version " + verStr)
|
||||
return verStr
|
||||
return verObj
|
||||
# print("path is" + ','.join(sys.path))
|
||||
|
|
|
@ -10,6 +10,6 @@ echo "prebuilt binaries for your computer into nanopb-0.4.4"
|
|||
cd proto
|
||||
../nanopb-0.4.4/generator-bin/protoc --nanopb_out=-v:../src/mesh/generated -I=../proto *.proto
|
||||
|
||||
echo "Regenerating protobuf documentation - if you see an error message"
|
||||
echo "you can ignore it unless doing a new protobuf release to github."
|
||||
bin/regen-docs.sh
|
||||
#echo "Regenerating protobuf documentation - if you see an error message"
|
||||
#echo "you can ignore it unless doing a new protobuf release to github."
|
||||
#bin/regen-docs.sh
|
|
@ -1,5 +1,5 @@
|
|||
set -e
|
||||
|
||||
echo "Converting to uf2 for NRF52 Adafruit bootloader"
|
||||
bin/uf2conv.py .pio/build/rak4631/firmware.hex -f 0xADA52840
|
||||
bin/uf2conv.py .pio/build/t-echo/firmware.hex -f 0xADA52840
|
||||
cp flash.uf2 /media/kevinh/FTH*BOOT/
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
set -e
|
||||
|
||||
echo "Converting to uf2 for NRF52 Adafruit bootloader"
|
||||
bin/uf2conv.py .pio/build/rak4631/firmware.hex -f 0xADA52840
|
||||
cp flash.uf2 /media/kevinh/FTH*BOOT/
|
|
@ -15,7 +15,7 @@
|
|||
],
|
||||
"usb_product": "TTGO_eink",
|
||||
"mcu": "nrf52840",
|
||||
"variant": "eink",
|
||||
"variant": "t-echo",
|
||||
"variants_dir": "variants",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
|
@ -44,17 +44,20 @@
|
|||
"arduino"
|
||||
],
|
||||
"name": "TTGO eink (Adafruit BSP)",
|
||||
"upload": {
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"require_upload_port": true,
|
||||
"speed": 115200,
|
||||
"protocol": "jlink",
|
||||
"protocols": [
|
||||
"jlink",
|
||||
"nrfjprog",
|
||||
"stlink"
|
||||
]
|
||||
"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": "FIXME",
|
||||
"vendor": "TTGO"
|
|
@ -4,6 +4,7 @@ You probably don't care about this section - skip to the next one.
|
|||
|
||||
## before next release
|
||||
|
||||
* turn on setTx(timeout) and state = setDioIrqParams(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT, SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT); in sx1262 code
|
||||
* pine64 lora module
|
||||
* nrf52 USB is unreliable while sleeping?
|
||||
* @havealoha fixedposition not working
|
||||
|
|
|
@ -16,7 +16,7 @@ default_envs = tbeam
|
|||
;default_envs = tlora_v1_3
|
||||
;default_envs = tlora-v2
|
||||
;default_envs = lora-relay-v1 # nrf board
|
||||
;default_envs = eink
|
||||
;default_envs = t-echo
|
||||
;default_envs = nrf52840dk-geeksville
|
||||
;default_envs = native # lora-relay-v1 # nrf52840dk-geeksville # linux # or if you'd like to change the default to something like lora-relay-v1 put that here
|
||||
;default_envs = rak4631
|
||||
|
@ -72,7 +72,7 @@ lib_deps =
|
|||
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
||||
https://github.com/meshtastic/arduino-fsm.git#829e967b8a95c094f73c60ef8dacfe66eae38940
|
||||
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
|
||||
https://github.com/meshtastic/RadioLib.git#07de964e929238949035fb0d5887026a3058df1a
|
||||
https://github.com/meshtastic/RadioLib.git#80ed10d689a0568782c5bd152906b0f97d2bce93
|
||||
https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79
|
||||
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
|
||||
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
||||
|
@ -89,6 +89,7 @@ lib_deps =
|
|||
${env.lib_deps}
|
||||
|
||||
build_flags = ${env.build_flags} -Os
|
||||
# -DRADIOLIB_GODMODE
|
||||
|
||||
src_filter = ${env.src_filter} -<portduino/>
|
||||
|
||||
|
@ -211,7 +212,7 @@ lib_ignore =
|
|||
monitor_port = /dev/ttyACM1
|
||||
|
||||
# we pass in options to jlink so it can understand freertos (note: we don't use "jlink" as the tool)
|
||||
debug_tool = jlink
|
||||
;debug_tool = jlink
|
||||
debug_port = :2331
|
||||
# Note: the ARGUMENTS MUST BE on multiple lines. Otherwise platformio/commands/debug/helpers.py misparses everything into the "executable"
|
||||
# attribute and leaves "arguments" empty
|
||||
|
@ -340,32 +341,33 @@ lib_deps =
|
|||
${arduino_base.lib_deps}
|
||||
|
||||
; First prototype eink/nrf52840/sx1262 device
|
||||
[env:eink]
|
||||
[env:t-echo]
|
||||
extends = nrf52840_base
|
||||
board = eink
|
||||
board = t-echo
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/eink
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/t-echo
|
||||
-DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/eink>
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/t-echo>
|
||||
lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
https://github.com/geeksville/EPD_Libraries.git
|
||||
TFT_eSPI
|
||||
;upload_protocol = fs
|
||||
|
||||
; First prototype eink/nrf52840/sx1262 device
|
||||
[env:eink0.1]
|
||||
extends = nrf52840_base
|
||||
board = eink0.1
|
||||
# add our variants files to the include and src paths
|
||||
# define build flags for the TFT_eSPI library
|
||||
build_flags = ${nrf52_base.build_flags} -Ivariants/eink0.1
|
||||
-DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
|
||||
src_filter = ${nrf52_base.src_filter} +<../variants/eink0.1>
|
||||
lib_deps =
|
||||
${nrf52840_base.lib_deps}
|
||||
https://github.com/geeksville/EPD_Libraries.git
|
||||
TFT_eSPI
|
||||
; First prototype eink/nrf52840/sx1262 device (removed from build because didn't ship in quantity)
|
||||
;[env:eink0.1]
|
||||
;extends = nrf52840_base
|
||||
;board = eink0.1
|
||||
;# add our variants files to the include and src paths
|
||||
;# define build flags for the TFT_eSPI library
|
||||
;build_flags = ${nrf52_base.build_flags} -Ivariants/eink0.1
|
||||
; -DBUSY_PIN=3 -DRST_PIN=2 -DDC_PIN=28 -DCS_PIN=30
|
||||
;src_filter = ${nrf52_base.src_filter} +<../variants/eink0.1>
|
||||
;lib_deps =
|
||||
; ${nrf52840_base.lib_deps}
|
||||
; https://github.com/geeksville/EPD_Libraries.git
|
||||
; TFT_eSPI
|
||||
|
||||
; The https://github.com/BigCorvus/SX1262-LoRa-BLE-Relay board by @BigCorvus
|
||||
[env:lora-relay-v1]
|
||||
|
@ -417,7 +419,7 @@ lib_deps =
|
|||
[env:native]
|
||||
platform = https://github.com/geeksville/platform-native.git
|
||||
src_filter = ${env.src_filter} -<esp32/> -<nimble/> -<nrf52/> -<mesh/http/> -<plugins/esp32>
|
||||
build_flags = ${arduino_base.build_flags} -O0
|
||||
build_flags = ${arduino_base.build_flags} -O0 -lgpiod
|
||||
framework = arduino
|
||||
board = native
|
||||
lib_deps =
|
||||
|
|
2
proto
2
proto
|
@ -1 +1 @@
|
|||
Subproject commit 157f9891dd35d3087f51e32dc0b103fcb1f0ca7c
|
||||
Subproject commit 5be5307c906f1275e4134f839b1d93283484932e
|
|
@ -120,7 +120,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||
|
||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
||||
/// in power
|
||||
virtual bool isVBUSPlug() { return getBattVoltage() > 1000 * chargingVolt; }
|
||||
virtual bool isVBUSPlug() { return getBattVoltage() > chargingVolt; }
|
||||
|
||||
/// Assume charging if we have a battery and external power is connected.
|
||||
/// we can't be smart enough to say 'full'?
|
||||
|
|
|
@ -32,6 +32,13 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
|||
emitRebooted();
|
||||
}
|
||||
|
||||
// For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages
|
||||
bool SerialConsole::checkIsConnected()
|
||||
{
|
||||
uint32_t now = millis();
|
||||
return (now - lastContactMsec) < getPref_phone_timeout_secs() * 1000UL;
|
||||
}
|
||||
|
||||
/**
|
||||
* we override this to notice when we've received a protobuf over the serial
|
||||
* stream. Then we shunt off debug serial output.
|
||||
|
@ -46,14 +53,3 @@ bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
|
|||
return StreamAPI::handleToRadio(buf, len);
|
||||
}
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
void SerialConsole::onConnectionChanged(bool connected)
|
||||
{
|
||||
if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api
|
||||
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
|
||||
} else {
|
||||
// FIXME, we get no notice of serial going away, we should instead automatically generate this event if we haven't
|
||||
// received a packet in a while
|
||||
powerFSM.trigger(EVENT_SERIAL_DISCONNECTED);
|
||||
}
|
||||
}
|
|
@ -25,8 +25,9 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
|
|||
}
|
||||
|
||||
protected:
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected);
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected();
|
||||
};
|
||||
|
||||
// A simple wrapper to allow non class aware code write to the console
|
||||
|
|
|
@ -413,6 +413,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#define HW_VENDOR HardwareModel_RAK4631
|
||||
|
||||
#elif defined(TTGO_T_ECHO)
|
||||
|
||||
#define HW_VENDOR HardwareModel_T_ECHO
|
||||
|
||||
#elif NRF52_SERIES
|
||||
|
||||
#define HW_VENDOR HardwareModel_NRF52_UNKNOWN
|
||||
|
@ -423,11 +427,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#define USE_SIM_RADIO
|
||||
|
||||
#define USE_RF95
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET RADIOLIB_NC
|
||||
#define LORA_DIO1 33 // Not really used
|
||||
#define LORA_DIO2 32 // Not really used
|
||||
// Pine64 uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
|
||||
// not found then probe for SX1262. Currently the RF95 code is disabled because I think the RF95 module won't need to ship.
|
||||
// #define USE_RF95
|
||||
#define USE_SX1262
|
||||
|
||||
// Fake SPI device selections
|
||||
#define RF95_SCK 5
|
||||
|
@ -435,6 +438,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#define RF95_MOSI 27
|
||||
#define RF95_NSS RADIOLIB_NC // the ch341f spi controller does CS for us
|
||||
|
||||
#define LORA_DIO0 26 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 14
|
||||
#define LORA_DIO1 33 // SX1262 IRQ, called DIO0 on pinelora schematic, pin 7 on ch341f "ack" - FIXME, enable hwints in linux
|
||||
#define LORA_DIO2 32 // SX1262 BUSY, actually connected to "DIO5" on pinelora schematic, pin 8 on ch341f "slct"
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#ifdef USE_SX1262
|
||||
#define SX1262_CS 20 // CS0 on pinelora schematic, hooked to gpio D0 on ch341f
|
||||
#define SX1262_DIO1 LORA_DIO1
|
||||
#define SX1262_BUSY LORA_DIO2
|
||||
#define SX1262_RESET LORA_RESET
|
||||
// HOPE RFM90 does not have a TCXO therefore not SX1262_E22
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// DEBUG LED
|
||||
|
|
|
@ -4,5 +4,8 @@
|
|||
|
||||
#include "mesh/generated/mesh.pb.h" // For CriticalErrorCode
|
||||
|
||||
/// A macro that include filename and line
|
||||
#define RECORD_CRITICALERROR(code) recordCriticalError(code, __LINE__, __FILE__)
|
||||
|
||||
/// Record an error that should be reported via analytics
|
||||
void recordCriticalError(CriticalErrorCode code = CriticalErrorCode_Unspecified, uint32_t address = 0);
|
||||
void recordCriticalError(CriticalErrorCode code = CriticalErrorCode_Unspecified, uint32_t address = 0, const char *filename = NULL);
|
||||
|
|
|
@ -49,13 +49,21 @@ bool perhapsSetRTC(RTCQuality q, const struct timeval *tv)
|
|||
|
||||
if (shouldSet) {
|
||||
lastSetMsec = now;
|
||||
#ifndef NO_ESP32
|
||||
settimeofday(tv, NULL);
|
||||
readFromRTC();
|
||||
#else
|
||||
|
||||
// This delta value works on all platforms
|
||||
timeStartMsec = now;
|
||||
zeroOffsetSecs = tv->tv_sec;
|
||||
|
||||
// If this platform has a setable RTC, set it
|
||||
#ifndef NO_ESP32
|
||||
settimeofday(tv, NULL);
|
||||
#endif
|
||||
|
||||
// nrf52 doesn't have a readable RTC (yet - software not written)
|
||||
#if defined(PORTDUINO) || !defined(NO_ESP32)
|
||||
readFromRTC();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -84,7 +92,7 @@ bool perhapsSetRTC(RTCQuality q, struct tm &t)
|
|||
|
||||
uint32_t getTime()
|
||||
{
|
||||
return ((millis() - timeStartMsec) / 1000) + zeroOffsetSecs;
|
||||
return (((uint32_t) millis() - timeStartMsec) / 1000) + zeroOffsetSecs;
|
||||
}
|
||||
|
||||
uint32_t getValidTime(RTCQuality minQuality)
|
||||
|
|
|
@ -43,7 +43,7 @@ bool UBloxGPS::setupGPS()
|
|||
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
|
||||
|
||||
if (!setUBXMode())
|
||||
recordCriticalError(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
|
|
@ -130,7 +130,7 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl
|
|||
// Draw version in upper right
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "%s",
|
||||
xstr(APP_VERSION)); // Note: we don't bother printing region or now, it makes the string too long
|
||||
xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long
|
||||
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf);
|
||||
screen->forceDisplay();
|
||||
|
||||
|
|
13
src/main.cpp
13
src/main.cpp
|
@ -299,6 +299,13 @@ uint32_t ButtonThread::longPressTime = 0;
|
|||
|
||||
RadioInterface *rIf = NULL;
|
||||
|
||||
/**
|
||||
* Some platforms (nrf52) might provide an alterate version that supresses calling delay from sleep.
|
||||
*/
|
||||
__attribute__ ((weak, noinline)) bool loopCanSleep() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
concurrency::hasBeenSetup = true;
|
||||
|
@ -459,7 +466,7 @@ void setup()
|
|||
// Do this after service.init (because that clears error_code)
|
||||
#ifdef AXP192_SLAVE_ADDRESS
|
||||
if (!axp192_found)
|
||||
recordCriticalError(CriticalErrorCode_NoAXP192); // Record a hardware fault for missing hardware
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_NoAXP192); // Record a hardware fault for missing hardware
|
||||
#endif
|
||||
|
||||
// Don't call screen setup until after nodedb is setup (because we need
|
||||
|
@ -550,7 +557,7 @@ void setup()
|
|||
airTime = new AirTime();
|
||||
|
||||
if (!rIf)
|
||||
recordCriticalError(CriticalErrorCode_NoRadio);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_NoRadio);
|
||||
else
|
||||
router->addInterface(rIf);
|
||||
|
||||
|
@ -640,7 +647,7 @@ void loop()
|
|||
mainController.nextThread->tillRun(millis())); */
|
||||
|
||||
// We want to sleep as long as possible here - because it saves power
|
||||
if (!runASAP)
|
||||
if (!runASAP && loopCanSleep())
|
||||
mainDelay.delay(delayMsec);
|
||||
// if (didWake) DEBUG_MSG("wake!\n");
|
||||
}
|
||||
|
|
|
@ -86,10 +86,11 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
|||
/// We only call plugins that are interested in the packet (and the message is destined to us or we are promiscious)
|
||||
bool wantsPacket = (isDecoded || pi.encryptedOk) && (pi.isPromiscuous || toUs) && pi.wantPacket(&mp);
|
||||
|
||||
DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket);
|
||||
assert(!pi.myReply); // If it is !null it means we have a bug, because it should have been sent the previous time
|
||||
|
||||
if (wantsPacket) {
|
||||
DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket);
|
||||
|
||||
pluginFound = true;
|
||||
|
||||
/// received channel (or NULL if not decoded)
|
||||
|
@ -97,17 +98,21 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
|||
|
||||
/// Is the channel this packet arrived on acceptable? (security check)
|
||||
/// Note: we can't know channel names for encrypted packets, so those are NEVER sent to boundChannel plugins
|
||||
bool rxChannelOk = !pi.boundChannel || (ch && ((mp.from == 0) || (strcmp(ch->settings.name, pi.boundChannel) == 0)));
|
||||
|
||||
/// Also: if a packet comes in on the local PC interface, we don't check for bound channels, because it is TRUSTED and it needs to
|
||||
/// to be able to fetch the initial admin packets without yet knowing any channels.
|
||||
|
||||
bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (ch && (strcmp(ch->settings.name, pi.boundChannel) == 0));
|
||||
|
||||
if (!rxChannelOk) {
|
||||
// no one should have already replied!
|
||||
assert(!currentReply);
|
||||
|
||||
if (mp.decoded.want_response) {
|
||||
DEBUG_MSG("packet on wrong channel, returning error\n");
|
||||
printPacket("packet on wrong channel, returning error", &mp);
|
||||
currentReply = pi.allocErrorResponse(Routing_Error_NOT_AUTHORIZED, &mp);
|
||||
} else
|
||||
DEBUG_MSG("packet on wrong channel, but client didn't want response\n");
|
||||
printPacket("packet on wrong channel, but can't respond", &mp);
|
||||
} else {
|
||||
|
||||
bool handled = pi.handleReceived(mp);
|
||||
|
@ -149,7 +154,9 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
|
|||
printPacket("Sending response", currentReply);
|
||||
service.sendToMesh(currentReply);
|
||||
currentReply = NULL;
|
||||
} else {
|
||||
} else if(mp.from != ourNodeNum) {
|
||||
// Note: if the message started with the local node we don't want to send a no response reply
|
||||
|
||||
// No one wanted to reply to this requst, tell the requster that happened
|
||||
DEBUG_MSG("No one responded, send a nak\n");
|
||||
|
||||
|
|
|
@ -541,15 +541,24 @@ NodeInfo *NodeDB::getOrCreateNode(NodeNum n)
|
|||
}
|
||||
|
||||
/// Record an error that should be reported via analytics
|
||||
void recordCriticalError(CriticalErrorCode code, uint32_t address)
|
||||
void recordCriticalError(CriticalErrorCode code, uint32_t address, const char *filename)
|
||||
{
|
||||
// Print error to screen and serial port
|
||||
String lcd = String("Critical error ") + code + "!\n";
|
||||
screen->print(lcd.c_str());
|
||||
DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address);
|
||||
if(filename)
|
||||
DEBUG_MSG("NOTE! Recording critical error %d at %s:%lx\n", code, filename, address);
|
||||
else
|
||||
DEBUG_MSG("NOTE! Recording critical error %d, address=%lx\n", code, address);
|
||||
|
||||
// Record error to DB
|
||||
myNodeInfo.error_code = code;
|
||||
myNodeInfo.error_address = address;
|
||||
myNodeInfo.error_count++;
|
||||
|
||||
// Currently portuino is mostly used for simulation. Make sue the user notices something really bad happend
|
||||
#ifdef PORTDUINO
|
||||
DEBUG_MSG("A critical failure occurred, portduino is exiting...");
|
||||
exit(2);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
|
|||
recentPackets.erase(recentPackets.begin() + i); // delete old record
|
||||
} else {
|
||||
if (r.id == p->id && r.sender == getFrom(p)) {
|
||||
DEBUG_MSG("Found existing packet record for fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
|
||||
DEBUG_MSG("Found existing packet record for fr=0x%x,to=0x%x,id=0x%x\n", p->from, p->to, p->id);
|
||||
|
||||
// Update the time on this record to now
|
||||
if (withUpdate)
|
||||
|
|
|
@ -27,6 +27,7 @@ PhoneAPI::~PhoneAPI()
|
|||
|
||||
void PhoneAPI::handleStartConfig()
|
||||
{
|
||||
// Must be before setting state (because state is how we know !connected)
|
||||
if (!isConnected()) {
|
||||
onConnectionChanged(true);
|
||||
observe(&service.fromNumChanged);
|
||||
|
@ -35,7 +36,7 @@ void PhoneAPI::handleStartConfig()
|
|||
// even if we were already connected - restart our state machine
|
||||
state = STATE_SEND_MY_INFO;
|
||||
|
||||
DEBUG_MSG("Reset nodeinfo read pointer\n");
|
||||
DEBUG_MSG("Starting API client config\n");
|
||||
nodeInfoForPhone = NULL; // Don't keep returning old nodeinfos
|
||||
nodeDB.resetReadPointer(); // FIXME, this read pointer should be moved out of nodeDB and into this class - because
|
||||
// this will break once we have multiple instances of PhoneAPI running independently
|
||||
|
@ -56,10 +57,9 @@ void PhoneAPI::close()
|
|||
void PhoneAPI::checkConnectionTimeout()
|
||||
{
|
||||
if (isConnected()) {
|
||||
uint32_t now = millis();
|
||||
bool newContact = (now - lastContactMsec) < getPref_phone_timeout_secs() * 1000UL;
|
||||
bool newContact = checkIsConnected();
|
||||
if (!newContact) {
|
||||
DEBUG_MSG("Timed out on phone contact, dropping phone connection\n");
|
||||
DEBUG_MSG("Lost phone connection\n");
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,8 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
|||
break;
|
||||
|
||||
default:
|
||||
DEBUG_MSG("Error: unexpected ToRadio variant\n");
|
||||
// Ignore nop messages
|
||||
// DEBUG_MSG("Error: unexpected ToRadio variant\n");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -50,9 +50,6 @@ class PhoneAPI
|
|||
/// Use to ensure that clients don't get confused about old messages from the radio
|
||||
uint32_t config_nonce = 0;
|
||||
|
||||
/** the last msec we heard from the client on the other side of this link */
|
||||
uint32_t lastContactMsec = 0;
|
||||
|
||||
public:
|
||||
PhoneAPI();
|
||||
|
||||
|
@ -88,12 +85,18 @@ class PhoneAPI
|
|||
/// Our fromradio packet while it is being assembled
|
||||
FromRadio fromRadioScratch;
|
||||
|
||||
/** the last msec we heard from the client on the other side of this link */
|
||||
uint32_t lastContactMsec = 0;
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected) {}
|
||||
|
||||
/// If we haven't heard from the other side in a while then say not connected
|
||||
void checkConnectionTimeout();
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() = 0;
|
||||
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
|
|
|
@ -94,15 +94,15 @@ bool RF95Interface::reconfigure()
|
|||
// configure publicly accessible settings
|
||||
int err = lora->setSpreadingFactor(sf);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora->setBandwidth(bw);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora->setCodingRate(cr);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora->setSyncWord(syncWord);
|
||||
assert(err == ERR_NONE);
|
||||
|
@ -115,13 +115,13 @@ bool RF95Interface::reconfigure()
|
|||
|
||||
err = lora->setFrequency(freq);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
if (power > MAX_POWER) // This chip has lower power limits than some
|
||||
power = MAX_POWER;
|
||||
err = lora->setOutputPower(power);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
startReceive(); // restart receiving
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ class RF95Interface : public RadioLibInterface
|
|||
public:
|
||||
RF95Interface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass &spi);
|
||||
|
||||
/// Some boards (Pinetab Lora module) have broken IRQ wires, so we need to poll via i2c registers
|
||||
bool isIRQPending() { return lora->getPendingIRQ(); }
|
||||
|
||||
/// Initialise the Driver transport hardware and software.
|
||||
|
|
|
@ -151,6 +151,9 @@ class RadioInterface
|
|||
*/
|
||||
float getFreq();
|
||||
|
||||
/// Some boards (1st gen Pinetab Lora module) have broken IRQ wires, so we need to poll via i2c registers
|
||||
virtual bool isIRQPending() { return false; }
|
||||
|
||||
protected:
|
||||
int8_t power = 17; // Set by applyModemConfig()
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ bool RadioLibInterface::canSendImmediately()
|
|||
// TX IRQ from the radio, the radio is probably broken.
|
||||
if (busyTx && (millis() - lastTxStart > 60000)) {
|
||||
DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n");
|
||||
recordCriticalError(CriticalErrorCode_TransmitFailed);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_TransmitFailed);
|
||||
#ifndef NO_ESP32
|
||||
if (busyTx && (millis() - lastTxStart > 65000)) // After 5s more, reboot
|
||||
ESP.restart();
|
||||
|
@ -312,7 +312,13 @@ void RadioLibInterface::startSend(MeshPacket *txp)
|
|||
size_t numbytes = beginSending(txp);
|
||||
|
||||
int res = iface->startTransmit(radiobuf, numbytes);
|
||||
assert(res == ERR_NONE);
|
||||
if(res != ERR_NONE) {
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_RadioSpiBug);
|
||||
|
||||
// This send failed, but make sure to 'complete' it properly
|
||||
completeSending();
|
||||
startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode)
|
||||
}
|
||||
|
||||
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
|
||||
enableInterrupt(isrTxLevel0);
|
||||
|
|
|
@ -49,6 +49,9 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
|
|||
|
||||
stopRetransmission(key);
|
||||
}
|
||||
else {
|
||||
DEBUG_MSG("didn't find pending packet\n");
|
||||
}
|
||||
}
|
||||
|
||||
return FloodingRouter::shouldFilterReceived(p);
|
||||
|
|
|
@ -59,6 +59,30 @@ bool SX1262Interface::init()
|
|||
res = lora.setDio2AsRfSwitch(false);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// Read/write a register we are not using (only used for FSK mode) to test SPI comms
|
||||
uint8_t crcLSB = 0;
|
||||
int err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
//if(crcLSB != 0x0f)
|
||||
// RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
crcLSB = 0x5a;
|
||||
err = lora.writeRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
err = lora.readRegister(SX126X_REG_CRC_POLYNOMIAL_LSB, &crcLSB, 1);
|
||||
if(err != ERR_NONE)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
|
||||
if(crcLSB != 0x5a)
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SX1262Failure);
|
||||
// If we got this far register accesses (and therefore SPI comms) are good
|
||||
#endif
|
||||
|
||||
if (res == ERR_NONE)
|
||||
res = lora.setCRC(SX126X_LORA_CRC_ON);
|
||||
|
||||
|
@ -78,15 +102,15 @@ bool SX1262Interface::reconfigure()
|
|||
// configure publicly accessible settings
|
||||
int err = lora.setSpreadingFactor(sf);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora.setBandwidth(bw);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
err = lora.setCodingRate(cr);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
// Hmm - seems to lower SNR when the signal levels are high. Leaving off for now...
|
||||
err = lora.setRxGain(true);
|
||||
|
@ -103,7 +127,7 @@ bool SX1262Interface::reconfigure()
|
|||
|
||||
err = lora.setFrequency(freq);
|
||||
if (err != ERR_NONE)
|
||||
recordCriticalError(CriticalErrorCode_InvalidRadioSetting);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_InvalidRadioSetting);
|
||||
|
||||
if (power > 22) // This chip has lower power limits than some
|
||||
power = 22;
|
||||
|
|
|
@ -25,6 +25,8 @@ class SX1262Interface : public RadioLibInterface
|
|||
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
|
||||
virtual bool sleep();
|
||||
|
||||
bool isIRQPending() { return lora.getIrqStatus() != 0; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Glue functions called from ISR land
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "StreamAPI.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#define START1 0x94
|
||||
|
@ -28,37 +29,42 @@ int32_t StreamAPI::readStream()
|
|||
uint8_t c = stream->read();
|
||||
|
||||
// Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
|
||||
size_t ptr = rxPtr++; // assume we will probably advance the rxPtr
|
||||
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) { // we have at least read our 4 byte 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
|
||||
|
||||
if (ptr == HEADER_LEN) {
|
||||
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 && ptr + 1 == len + HEADER_LEN) {
|
||||
rxPtr = 0; // start over again on the next packet
|
||||
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
|
||||
if (handleToRadio(rxBuf + HEADER_LEN, len))
|
||||
return 0; // we want to be called again ASAP because we still have more work to do
|
||||
}
|
||||
// If we didn't just fail the packet and we now have the right # of bytes, parse it
|
||||
handleToRadio(rxBuf + HEADER_LEN, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we had packets available this time, so assume we might have them next time also
|
||||
// we had bytes available this time, so assume we might have them next time also
|
||||
lastRxMsec = now;
|
||||
return 0;
|
||||
}
|
||||
|
@ -110,3 +116,17 @@ void StreamAPI::emitRebooted()
|
|||
// DEBUG_MSG("Emitting reboot packet for serial shell\n");
|
||||
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));
|
||||
}
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
void StreamAPI::onConnectionChanged(bool connected)
|
||||
{
|
||||
// FIXME do reference counting instead
|
||||
|
||||
if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api
|
||||
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
|
||||
} else {
|
||||
// FIXME, we get no notice of serial going away, we should instead automatically generate this event if we haven't
|
||||
// received a packet in a while
|
||||
powerFSM.trigger(EVENT_SERIAL_DISCONNECTED);
|
||||
}
|
||||
}
|
|
@ -67,6 +67,11 @@ class StreamAPI : public PhoneAPI, protected concurrency::OSThread
|
|||
*/
|
||||
void emitRebooted();
|
||||
|
||||
virtual void onConnectionChanged(bool connected);
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() = 0;
|
||||
|
||||
/**
|
||||
* Send the current txBuffer over our stream
|
||||
*/
|
||||
|
|
|
@ -46,7 +46,9 @@ typedef enum _CriticalErrorCode {
|
|||
CriticalErrorCode_NoAXP192 = 6,
|
||||
CriticalErrorCode_InvalidRadioSetting = 7,
|
||||
CriticalErrorCode_TransmitFailed = 8,
|
||||
CriticalErrorCode_Brownout = 9
|
||||
CriticalErrorCode_Brownout = 9,
|
||||
CriticalErrorCode_SX1262Failure = 10,
|
||||
CriticalErrorCode_RadioSpiBug = 11
|
||||
} CriticalErrorCode;
|
||||
|
||||
typedef enum _Routing_Error {
|
||||
|
@ -216,8 +218,8 @@ typedef struct _ToRadio {
|
|||
#define _Constants_ARRAYSIZE ((Constants)(Constants_DATA_PAYLOAD_LEN+1))
|
||||
|
||||
#define _CriticalErrorCode_MIN CriticalErrorCode_None
|
||||
#define _CriticalErrorCode_MAX CriticalErrorCode_Brownout
|
||||
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_Brownout+1))
|
||||
#define _CriticalErrorCode_MAX CriticalErrorCode_RadioSpiBug
|
||||
#define _CriticalErrorCode_ARRAYSIZE ((CriticalErrorCode)(CriticalErrorCode_RadioSpiBug+1))
|
||||
|
||||
#define _Routing_Error_MIN Routing_Error_NONE
|
||||
#define _Routing_Error_MAX Routing_Error_NOT_AUTHORIZED
|
||||
|
|
|
@ -40,7 +40,9 @@ class HttpAPI : public PhoneAPI
|
|||
// Nothing here yet
|
||||
|
||||
protected:
|
||||
// Nothing here yet
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() { return true; } // FIXME, be smarter about this
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "WiFiServerAPI.h"
|
||||
#include "PowerFSM.h"
|
||||
#include "configuration.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
|
@ -26,18 +25,7 @@ WiFiServerAPI::~WiFiServerAPI()
|
|||
// FIXME - delete this if the client dropps the connection!
|
||||
}
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
void WiFiServerAPI::onConnectionChanged(bool connected)
|
||||
{
|
||||
// FIXME - we really should be doing global reference counting to see if anyone is currently using serial or wifi and if so,
|
||||
// block sleep
|
||||
|
||||
if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api
|
||||
powerFSM.trigger(EVENT_SERIAL_CONNECTED);
|
||||
} else {
|
||||
powerFSM.trigger(EVENT_SERIAL_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
/// override close to also shutdown the TCP link
|
||||
void WiFiServerAPI::close()
|
||||
|
@ -46,6 +34,12 @@ void WiFiServerAPI::close()
|
|||
StreamAPI::close();
|
||||
}
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
bool WiFiServerAPI::checkIsConnected()
|
||||
{
|
||||
return client.connected();
|
||||
}
|
||||
|
||||
int32_t WiFiServerAPI::runOnce()
|
||||
{
|
||||
if (client.connected()) {
|
||||
|
|
|
@ -21,10 +21,11 @@ class WiFiServerAPI : public StreamAPI
|
|||
virtual void close();
|
||||
|
||||
protected:
|
||||
/// Hookable to find out when connection changes
|
||||
virtual void onConnectionChanged(bool connected);
|
||||
|
||||
virtual int32_t runOnce(); // Check for dropped client connections
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,6 +31,10 @@ void BluetoothPhoneAPI::onNowHasData(uint32_t fromRadioNum)
|
|||
}
|
||||
}
|
||||
|
||||
bool BluetoothPhoneAPI::checkIsConnected() {
|
||||
return curConnectionHandle >= 0;
|
||||
}
|
||||
|
||||
int toradio_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
|
||||
{
|
||||
auto om = ctxt->om;
|
||||
|
|
|
@ -6,10 +6,14 @@ extern uint16_t fromNumValHandle;
|
|||
|
||||
class BluetoothPhoneAPI : public PhoneAPI
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* Subclasses can use this as a hook to provide custom notifications for their transport (i.e. bluetooth notifies)
|
||||
*/
|
||||
virtual void onNowHasData(uint32_t fromRadioNum);
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected();
|
||||
};
|
||||
|
||||
extern PhoneAPI *bluetoothPhoneAPI;
|
|
@ -19,6 +19,10 @@ static inline void debugger_break(void)
|
|||
"mov pc, lr\n\t");
|
||||
}
|
||||
|
||||
bool loopCanSleep() {
|
||||
return !tud_cdc_connected();
|
||||
}
|
||||
|
||||
// handle standard gcc assert failures
|
||||
void __attribute__((noreturn)) __assert_func(const char *file, int line, const char *func, const char *failedexpr)
|
||||
{
|
||||
|
@ -104,7 +108,7 @@ void checkSDEvents()
|
|||
while (NRF_SUCCESS == sd_evt_get(&evt)) {
|
||||
switch (evt) {
|
||||
case NRF_EVT_POWER_FAILURE_WARNING:
|
||||
recordCriticalError(CriticalErrorCode_Brownout);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_Brownout);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -114,7 +118,7 @@ void checkSDEvents()
|
|||
}
|
||||
} else {
|
||||
if (NRF_POWER->EVENTS_POFWARN)
|
||||
recordCriticalError(CriticalErrorCode_Brownout);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_Brownout);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,10 +30,11 @@ void AdminPlugin::handleGetRadio(const MeshPacket &req)
|
|||
AdminMessage r = AdminMessage_init_default;
|
||||
r.get_radio_response = radioConfig;
|
||||
|
||||
// NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior.
|
||||
// NOTE: The phone app needs to know the ls_secs & phone_timeout value so it can properly expect sleep behavior.
|
||||
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
|
||||
// using to the app (so that even old phone apps work with new device loads).
|
||||
r.get_radio_response.preferences.ls_secs = getPref_ls_secs();
|
||||
r.get_radio_response.preferences.phone_timeout_secs = getPref_phone_timeout_secs();
|
||||
|
||||
r.which_variant = AdminMessage_get_radio_response_tag;
|
||||
myReply = allocDataProtobuf(r);
|
||||
|
|
|
@ -176,5 +176,5 @@ bool ExternalNotificationPlugin::handleReceived(const MeshPacket &mp)
|
|||
|
||||
#endif
|
||||
|
||||
return true; // Let others look at this message also if they want
|
||||
return false; // Very important to never return TRUE here. TRUE means we handled the packet and we will stop letting other plugins see it
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <Utility.h>
|
||||
#include <assert.h>
|
||||
#include <linux/gpio/LinuxGPIOPin.h>
|
||||
|
||||
// FIXME - move setBluetoothEnable into a HALPlatform class
|
||||
|
||||
|
@ -21,33 +22,14 @@ void cpuDeepSleep(uint64_t msecs)
|
|||
|
||||
void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel");
|
||||
|
||||
/** Dear pinetab hardware geeks!
|
||||
*
|
||||
* The current pinetab lora module has a slight bug. The ch341 part only provides ISR assertions on edges.
|
||||
* This makes sense because USB interrupts happen through fast/repeated special irq urbs that are constantly
|
||||
* chattering on the USB bus.
|
||||
*
|
||||
* But this isn't sufficient for level triggered ISR sources like the sx127x radios. The common way that seems to
|
||||
* be addressed by cs341 users is to **always** connect the INT# (pin 26 on the ch341f) signal to one of the GPIO signals
|
||||
* on the part. I'd recommend connecting that LORA_DIO0/INT# line to pin 19 (data 4) on the pinetab board. This would
|
||||
* provide an efficent mechanism so that the (kernel) code in the cs341 driver that I've slightly hacked up to see the
|
||||
* current state of LORA_DIO0. Without that access, I can't know if the interrupt is still pending - which would create
|
||||
* race conditions in packet handling.
|
||||
*
|
||||
* My workaround is to poll the status register internally to the sx127x. Which is expensive because it involves a number of
|
||||
* i2c transactions and many trips back and forth between kernel and my userspace app. I think shipping the current version
|
||||
* of the pinetab lora device would be fine because I can poll slowly (because lora is slow). But if you ever have cause to
|
||||
* rev this board. I highly encourage this small change.
|
||||
*
|
||||
* Btw - your little "USB lora dongle" is really neat. I encourage you to sell it, because even non pinetab customers could
|
||||
* use it to easily add lora to rasberry pi, desktop pcs etc...
|
||||
*
|
||||
|
||||
/** a simulated pin for busted IRQ hardware
|
||||
* Porduino helper class to do this i2c based polling:
|
||||
*/
|
||||
class R595PolledIrqPin : public GPIOPin
|
||||
class PolledIrqPin : public GPIOPin
|
||||
{
|
||||
public:
|
||||
R595PolledIrqPin() : GPIOPin(LORA_DIO0, "LORA_DIO0") {}
|
||||
PolledIrqPin() : GPIOPin(LORA_DIO1, "loraIRQ") {}
|
||||
|
||||
/// Read the low level hardware for this pin
|
||||
virtual PinStatus readPinHardware()
|
||||
|
@ -58,14 +40,16 @@ class R595PolledIrqPin : public GPIOPin
|
|||
extern RadioInterface *rIf; // FIXME, temporary hack until we know if we need to keep this
|
||||
|
||||
assert(rIf);
|
||||
RF95Interface *rIf95 = static_cast<RF95Interface *>(rIf);
|
||||
RadioLibInterface *rIf95 = static_cast<RadioLibInterface *>(rIf);
|
||||
bool p = rIf95->isIRQPending();
|
||||
// log(SysGPIO, LogDebug, "R595PolledIrqPin::readPinHardware(%s, %d, %d)", getName(), getPinNum(), p);
|
||||
log(SysGPIO, LogDebug, "PolledIrqPin::readPinHardware(%s, %d, %d)", getName(), getPinNum(), p);
|
||||
return p ? HIGH : LOW;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
GPIOPin *loraIrq;
|
||||
|
||||
/** apps run under portduino can optionally define a portduinoSetup() to
|
||||
* use portduino specific init code (such as gpioBind) to setup portduino on their host machine,
|
||||
* before running 'arduino' code.
|
||||
|
@ -74,8 +58,26 @@ void portduinoSetup()
|
|||
{
|
||||
printf("Setting up Meshtastic on Porduino...\n");
|
||||
|
||||
// FIXME: disable while not testing with real hardware
|
||||
// gpioBind(new R595PolledIrqPin());
|
||||
// FIXME: remove this hack once interrupts are confirmed to work on new pine64 board
|
||||
// loraIrq = new PolledIrqPin();
|
||||
loraIrq = new LinuxGPIOPin(LORA_DIO1, "ch341", "int", "loraIrq"); // or "err"?
|
||||
loraIrq->setSilent();
|
||||
gpioBind(loraIrq);
|
||||
|
||||
// BUSY hw was busted on current board - just use the simulated pin (which will read low)
|
||||
auto busy = new LinuxGPIOPin(SX1262_BUSY, "ch341", "slct", "loraBusy");
|
||||
busy->setSilent();
|
||||
gpioBind(busy);
|
||||
//auto fakeBusy = new SimGPIOPin(SX1262_BUSY, "fakeBusy");
|
||||
//fakeBusy->writePin(LOW);
|
||||
//fakeBusy->setSilent(true);
|
||||
//gpioBind(fakeBusy);
|
||||
|
||||
gpioBind(new LinuxGPIOPin(SX1262_RESET, "ch341", "ini", "loraReset"));
|
||||
|
||||
auto loraCs = new LinuxGPIOPin(SX1262_CS, "ch341", "cs0", "loraCs");
|
||||
loraCs->setSilent();
|
||||
gpioBind(loraCs);
|
||||
|
||||
// gpioBind((new SimGPIOPin(LORA_RESET, "LORA_RESET")));
|
||||
// gpioBind((new SimGPIOPin(RF95_NSS, "RF95_NSS"))->setSilent());
|
||||
|
|
|
@ -127,7 +127,7 @@ static void waitEnterSleep()
|
|||
delay(100); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives)
|
||||
|
||||
if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep
|
||||
recordCriticalError(CriticalErrorCode_SleepEnterWait);
|
||||
RECORD_CRITICALERROR(CriticalErrorCode_SleepEnterWait);
|
||||
assert(0); // FIXME - for now we just restart, need to fix bug #167
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -92,6 +92,8 @@ Note: Turning off EINK PWR_ON produces no noticeable power savings over just put
|
|||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#define TTGO_T_ECHO
|
||||
|
||||
// Number of pins defined in PinDescription array
|
||||
#define PINS_COUNT (48)
|
||||
#define NUM_DIGITAL_PINS (48)
|
||||
|
@ -231,8 +233,6 @@ External serial flash WP25R1635FZUIL0
|
|||
#define PIN_GPS_TX (32 + 9) // This is for bits going TOWARDS the CPU
|
||||
#define PIN_GPS_RX (32 + 8) // This is for bits going TOWARDS the GPS
|
||||
|
||||
#define HAS_AIR530_GPS
|
||||
|
||||
#define PIN_SERIAL1_RX PIN_GPS_TX
|
||||
#define PIN_SERIAL1_TX PIN_GPS_RX
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
[VERSION]
|
||||
major = 1
|
||||
minor = 2
|
||||
build = 29
|
||||
build = 30
|
||||
|
|
Ładowanie…
Reference in New Issue