mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-24 18:23:08 +00:00

* 2.6 protos * [create-pull-request] automated change (#5789) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Hello world support for UDP broadcasts over the LAN on ESP32 (#5779) * UDP local area network meshing on ESP32 * Logs * Comment * Update UdpMulticastThread.h * Changes * Only use router->send * Make NodeDatabase (and file) independent of DeviceState (#5813) * Make NodeDatabase (and file) independent of DeviceState * 70 * Remove logging statement no longer needed * Explicitly set CAD symbols, improve slot time calculation and adjust CW size accordingly (#5772) * File system persistence fixes * [create-pull-request] automated change (#6000) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Update ref * Back to 80 * [create-pull-request] automated change (#6002) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * 2.6 <- Next hop router (#6005) * Initial version of NextHopRouter * Set original hop limit in header flags * Short-circuit to FloodingRouter for broadcasts * If packet traveled 1 hop, set `relay_node` as `next_hop` for the original transmitter * Set last byte to 0xFF if it ended at 0x00 As per an idea of @S5NC * Also update next-hop based on received DM for us * temp * Add 1 retransmission for intermediate hops when using NextHopRouter * Add next_hop and relayed_by in PacketHistory for setting next-hop and handle flooding fallback * Update protos, store multiple relayers * Remove next-hop update logic from NeighborInfoModule * Fix retransmissions * Improve ACKs for repeated packets and responses * Stop retransmission even if there's not relay node * Revert perhapsRebroadcast() * Remove relayer if we cancel a transmission * Better checking for fallback to flooding * Fix newlines in traceroute print logs * Stop retransmission for original packet * Use relayID * Also when want_ack is set, we should try to retransmit * Fix cppcheck error * Fix 'router' not in scope error * Fix another cppcheck error * Check for hop_limit and also update next hop when `hop_start == hop_limit` on ACK Also check for broadcast in `getNextHop()` * Formatting and correct NUM_RETRANSMISSIONS * Update protos * Start retransmissions in NextHopRouter if ReliableRouter didn't do it * Handle repeated/fallback to flooding packets properly First check if it's not still in the TxQueue * Guard against clients setting `next_hop`/`relay_node` * Don't cancel relay if we were the assigned next-hop * Replies (e.g. tapback emoji) are also a valid confirmation of receipt --------- Co-authored-by: GUVWAF <thijs@havinga.eu> Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com> Co-authored-by: Tom Fifield <tom@tomfifield.net> Co-authored-by: GUVWAF <78759985+GUVWAF@users.noreply.github.com> * fix "native" compiler errors/warnings NodeDB.h * fancy T-Deck / SenseCAP Indicator / unPhone / PICOmputer-S3 TFT screen (#3259) * lib update: light theme * fix merge issue * lib update: home buttons + button try-fix * lib update: icon color fix * lib update: fix instability/crash on notification * update lib: timezone * timezone label * lib update: fix set owner * fix spiLock in RadioLibInterface * add picomputer tft build * picomputer build * fix compiler error std::find() * fix merge * lib update: theme runtime config * lib update: packet logger + T-Deck Plus * lib update: mesh detector * lib update: fix brightness & trackball crash * try-fix less paranoia * sensecap indicator updates * lib update: indicator fix * lib update: statistic & some fixes * lib-update: other T-Deck touch driver * use custom touch driver for Indicator * lower tft task prio * prepare LVGL ST7789 driver * lib update: try-fix audio * Drop received packets from self * Additional decoded packet ignores * Honor flip & color for Heltec T114 and T190 (#4786) * Honor TFT_MESH color if defined for Heltec T114 or T190 * Temporary: point lib_deps at fork of Heltec's ST7789 library For demo only, until ST7789 is merged * Update lib_deps; tidy preprocessor logic * Download debian files after firmware zip * set title for protobufs bump PR (#4792) * set title for version bump PR (#4791) * Enable Dependabot * chore: trunk fmt * fix dependabot syntax (#4795) * fix dependabot syntax * Update dependabot.yml * Update dependabot.yml * Bump peter-evans/create-pull-request from 6 to 7 in /.github/workflows (#4797) * Bump docker/build-push-action from 5 to 6 in /.github/workflows (#4800) * Actions: Semgrep Images have moved from returntocorp to semgrep (#4774) https://hub.docker.com/r/returntocorp/semgrep notes: "We've moved! Official Docker images for Semgrep now available at semgrep/semgrep." Patch updates our CI workflow for these images. Co-authored-by: Ben Meadors <benmmeadors@gmail.com> * Bump meshtestic from `31ee3d9` to `37245b3` (#4799) Bumps [meshtestic](https://github.com/meshtastic/meshTestic) from `31ee3d9` to `37245b3`. - [Commits](31ee3d90c8...37245b3d61
) --- updated-dependencies: - dependency-name: meshtestic dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * [create-pull-request] automated change (#4789) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Bump pnpm/action-setup from 2 to 4 in /.github/workflows (#4798) Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 2 to 4. - [Release notes](https://github.com/pnpm/action-setup/releases) - [Commits](https://github.com/pnpm/action-setup/compare/v2...v4) --- updated-dependencies: - dependency-name: pnpm/action-setup dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Raspberry Pico2 - needs protos * Re-order doDeepSleep (#4802) Make sure PMU sleep takes place before I2C ends * [create-pull-request] automated change * heltec-wireless-bridge requires Proto PR first * feat: trigger class update when protobufs are changed * meshtastic/ is a test suite; protobufs/ contains protobufs; * Update platform-native to pick up portduino crash fix (#4807) * Hopefully extract and commit to meshtastic.github.io * CI fixes * [Board] DIY "t-energy-s3_e22" (#4782) * New variant "t-energy-s3_e22" - Lilygo T-Energy-S3 - NanoVHF "Mesh-v1.06-TTGO-T18" board - Ebyte E22 Series * add board_level = extra * Update variant.h --------- Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com> Co-authored-by: Tom Fifield <tom@tomfifield.net> * Consolidate variant build steps (#4806) * poc: consolidate variant build steps * use build-variant action * only checkout once and clean up after run * Revert "Consolidate variant build steps (#4806)" (#4816) This reverts commit9f8d86cb25
. * Make Ublox code more readable (#4727) * Simplify Ublox code Ublox comes in a myriad of versions and settings. Presently our configuration code does a lot of branching based on versions being or not being present. This patch adds version detection earlier in the piece and branches on the set gnssModel instead to create separate setup methods for Ublox 6, Ublox 7/8/9, and Ublox10. Additionally, adds a macro to make the code much shorter and more readable. * Make trunk happy * Make trunk happy --------- Co-authored-by: Ben Meadors <benmmeadors@gmail.com> * Consider the LoRa header when checking packet length * Minor fix (#4666) * Minor fixes It turns out setting a map value with the index notation causes an lookup that can be avoided with emplace. Apply this to one line in the StoreForward module. Fix also Cppcheck-determined highly minor performance increase by passing gpiochipname as a const reference :) The amount of cycles used on this laptop while learning about these callouts from cppcheck is unlikely to ever be more than the cycles saved by the fixes ;) * Update PortduinoGlue.cpp * Revert "Update classes on protobufs update" (#4824) * Revert "Update classes on protobufs update" * remove quotes to fix trunk. --------- Co-authored-by: Tom Fifield <tom@tomfifield.net> * Implement optional second I2C bus for NRF52840 Enabled at compile-time if WIRE_INFERFACES_COUNT defined as 2 * Add I2C bus to Heltec T114 header pins SDA: P0.13 SCL: P0.16 Uses bus 1, leaving bus 0 routed to the unpopulated footprint for the RTC (general future-proofing) * Tidier macros * Swap SDA and SCL SDA=P0.16, SCL=P0.13 * Refactor and consolidate time window logic (#4826) * Refactor and consolidate windowing logic * Trunk * Fixes * More * Fix braces and remove unused now variables. There was a brace in src/mesh/RadioLibInterface.cpp that was breaking compile on some architectures. Additionally, there were some brace errors in src/modules/Telemetry/AirQualityTelemetry.cpp src/modules/Telemetry/EnvironmentTelemetry.cpp src/mesh/wifi/WiFiAPClient.cpp Move throttle include in WifiAPClient.cpp to top. Add Default.h to sleep.cpp rest of files just remove unused now variables. * Remove a couple more meows --------- Co-authored-by: Tom Fifield <tom@tomfifield.net> * Rename message length headers and set payload max to 255 (#4827) * Rename message length headers and set payload max to 255 * Add MESHTASTIC_PKC_OVERHEAD * compare to MESHTASTIC_HEADER_LENGTH --------- Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com> * Check for null before printing debug (#4835) * fix merge * try-fix crash * lib update: fix neighbors * fix GPIO0 mode after I2S audio * lib update: audio fix * lib update: fixes and improvements * extra * added ILI9342 (from master) * device-ui persistency * review update * fix request, add handled * fix merge issue * fix merge issue * remove newline * remove newlines from debug log * playing with locks; but needs more testing * diy mesh-tab initial files * board definition for mesh-tab (not yet used) * use DISPLAY_SET_RESOLUTION to avoid hw dependency in code * no telemetry for Indicator * 16MB partition for Indicator * 8MB partition for Indicator * stability: add SPI lock before saving via littleFS * dummy for config transfer (#5154) * update indicator (due to compile and linker errors) * remove faulty partition line * fix missing include * update indicator board * update mesh-tab ILI9143 TFT * fix naming * mesh-tab targets * try: disable duplicate locks * fix nodeDB erase loop when free mem returns invalid value (0, -1). * upgrade toolchain for nrf52 to gcc 9.3.1 * try-fix (workaround) T-Deck audio crash * update mesh-tab tft configs * set T-Deck audio to unused 48 (mem mclk) * swap mclk to gpio 21 * update meshtab voltage divider * update mesh-tab ini * Fixed the issue that indicator device uploads via rp2040 serial port in some cases. * Fixed the issue that the touch I2C address definition was not effective. * Fixed the issue that the wifi configuration saved to RAM did not take effect. * rotation fix; added ST7789 3.2" display * dreamcatcher: assign GPIO44 to audio mclk * mesh-tab touch updates * add mesh-tab powersave as default * fix DIO1 wakeup * mesh-tab: enable alert message menu * Streamline board definitions for first tech preview. (#5390) * Streamline board definitions for first tech preview. TBD: Indicator Support * add point-of-checkin * use board/unphone.json --------- Co-authored-by: mverch67 <manuel.verch@gmx.de> * fix native targets * add RadioLib debugging options for (T-Deck) * fix T-Deck build * fix native tft targets for rpi * remove wrong debug defines * t-deck-tft button is handled in device-ui * disable default lightsleep for indicator * Windows Support - Trunk and Platformio (#5397) * Add support for GPG * Add usb device support * Add trunk.io to devcontainer * Trunk things * trunk fmt * formatting * fix trivy/DS002, checkov/CKV_DOCKER_3 * hide docker extension popup * fix trivy/DS026, checkov/CKV_DOCKER_2 * fix radioLib warnings for T-Deck target * wake screen with button only * use custom touch driver * define wake button for unphone * use board definition for mesh-tab * mesh-tab rotation upside-down * update platform native * use MESH_TAB hardware model definition * radioLib update (fix crash/assert) * reference seeed indicator fix commit arduino-esp32 * Remove unneeded file change :) * disable serial module and tcp socket api for standalone devices (#5591) * disable serial module and tcp socket api for standalone devices * just disable webserver, leave wifi available * disable socket api * mesh-tab: lower I2C touch frequency * log error when packet queue is full * add more locking for shared SPI devices (#5595) * add more locking for shared SPI devices * call initSPI before the lock is used * remove old one * don't double lock * Add missing unlock * More missing unlocks * Add locks to SafeFile, remove from `readcb`, introduce some LockGuards * fix lock in setupSDCard() * pull radiolib trunk with SPI-CS fixes * change ContentHandler to Constructor type locks, where applicable --------- Co-authored-by: mverch67 <manuel.verch@gmx.de> Co-authored-by: GUVWAF <thijs@havinga.eu> Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com> * T-Deck: revert back to lovyanGFX touch driver * T-Deck: increase allocated PSRAM by 50% * mesh-tab: streamline target definitions * update RadioLib 7.1.2 * mesh-tab: fix touch rotation 4.0 inch display * Mesh-Tab platformio: 4.0inch: increase SPI frequency to max * mesh-tab: fix rotation for 3.5 IPS capacitive display * mesh-tab: fix rotation for 3.2 IPS capacitive display * restructure device-ui library into sub-directories * preparations for generic DisplayDriverFactory * T-Deck: increase LVGL memory size * update lib * trunk fmt --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Ben Meadors <benmmeadors@gmail.com> Co-authored-by: todd-herbert <herbert.todd@gmail.com> Co-authored-by: Jason Murray <15822260+scruplelesswizard@users.noreply.github.com> Co-authored-by: Jason Murray <jason@chaosaffe.io> Co-authored-by: Tom Fifield <tom@tomfifield.net> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com> Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz> Co-authored-by: Austin <vidplace7@gmail.com> Co-authored-by: virgil <virgil.wang.cj@gmail.com> Co-authored-by: Mark Trevor Birss <markbirss@gmail.com> Co-authored-by: Kalle Lilja <15094562+ThatKalle@users.noreply.github.com> Co-authored-by: GUVWAF <thijs@havinga.eu> * Version this * Update platformio.ini (#6006) * tested higher speed and it works * Un-extra * Add -tft environments to the ci matrix * Exclude unphone tft for now. Something is wonky * fixed Indicator touch issue (causing IO expander issues), added more RAM * update lib * fixed Indicator touch issue (causing IO expander issues), added more RAM (#6013) * increase T-Deck PSRAM to avoid too early out-of-memory when messages fill up the storage * update device-ui lib * Fix T-Deck SD card detection (#6023) * increase T-Deck PSRAM to avoid too early out-of-memory when messages fill up the storage * fix SDCard for T-Deck; allow SPI frequency config * meshtasticd: Add X11 480x480 preset (#6020) * Littlefs per device * 2.6 update * [create-pull-request] automated change (#6037) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * InkHUD UI for E-Ink (#6034) * Decouple ButtonThread from sleep.cpp Reorganize sleep observables. Don't call ButtonThread methods inside doLightSleep. Instead, handle in class with new lightsleep Observables. * InkHUD: initial commit (WIP) Publicly discloses the current work in progress. Not ready for use. * feat: battery icon * chore: implement meshtastic/firmware #5454 Clean up some inline functions * feat: menu & settings for "jump to applet" * Remove the beforeRender pattern It hugely complicates things. If we can achieve acceptable performance without it, so much the better. * Remove previous Map Applet Needs re-implementation to work without the beforeRender pattern * refactor: reimplement map applet Doesn't require own position Doesn't require the beforeRender pattern to precalculate; now all-at-once in render Lays groundwork for fixed-size map with custom background image * feat: autoshow Allow user to select which applets (if any) should be automatically brought to foreground when they have new data to display * refactor: tidy-up applet constructors misc. jobs including: - consistent naming - move initializer-list-only constructors to header - give derived applets unique identifiers for MeshModule and OSThread logging * hotfix: autoshow always uses FAST update In future, it *will* often use FAST, but this will be controlled by a WindowManager component which has not yet been written. Hotfixed, in case anybody is attempting to use this development version on their deployed devices. * refactor: bringToForeground no longer requests FAST update In situations where an applet has moved to foreground because of user input, requestUpdate can be manually called, to upgrade to FAST refresh. More permanent solution for #23e1dfc * refactor: extract string storage from ThreadedMessageApplet Separates the code responsible for storing the limited message history, which was previously part of the ThreadedMessageApplet. We're now also using this code to store the "most recent message". Previously, this was stored in the `InkHUD::settings` struct, which was much less space-efficient. We're also now storing the latest DM, laying the foundation for an applet to display only DMs, which will complement the threaded message applet. * fix: text wrapping Attempts to fix a disparity between `Applet::printWrapped` and `Applet::getWrappedTextHeight`, which would occasionally cause a ThreadedMessageApplet message to render "too short", overlapping other text. * fix: purge old constructor This one slipped through the last commit.. * feat: DM Applet Useful in combination with the ThreadedMessageApplets, which don't show DMs * fix: applets shouldn't handle events while deactivated Only one or two applets were actually doing this, but I'm making a habit of having all applets return early from their event handling methods (as good practice), even if those methods are disabled elsewhere (e.g. not observing observable, return false from wantPacket) * refactor: allow requesting update without requesting autoshow Some applets may want to redraw, if they are displayed, but not feel the information is worth being brought to foreground for. Example: ActiveNodesApplet, when purging old nodes from list. * feat: custom "Recently Active" duration Allows users to tailor how long nodes will appear in the "Recents" applets, to suit the activity level of their mesh. * refactor: rename some applets * fix: autoshow * fix: getWrappedTextHeight Remove the "simulate" option from printWrapped; too hard to keep inline with genuine printing (because of AdafruitGFX Fonts' xAdvance, mabye?). Instead of simulating, we printWrapped as normal, and discard pixel output by setting crop. Both methods are similarly inefficient, apparently. * fix: text wrapping in ThreadedMessageApplet Wrong arguments were passed to Applet::printWrapped * feat: notifications for text messages Only shown if current applet does not already display the same info. Autoshow takes priority over notifications, if both would be used to display the same info. * feat: optimize FAST vs FULL updates New UpdateMediator class counts the number of each update type, and suggets which one to use, if the code doesn't already have an explicit prefence. Also performs "maintenance refreshes" unprovoked if display is not given an opportunity to before a FULL refresh through organic use. * chore: update todo list * fix: rare lock-up of buttons * refactor: backlight Replaces the initial proof-of-concept frontlight code for T-Echo Presses less than 5 seconds momentarily illuminate the display Presses longer than 5 seconds latch the light, requiring another tap to disable If user has previously removed the T-Echo's capacitive touch button (some DIY projects), the light is controlled by the on-screen menu. This fallback is used by all T-Echo devices, until a press of the capacitive touch button is detected. * feat: change tile with aux button Applied to VM-E290. Working as is, but a refactor of WindowManager::render is expected shortly, which will also tidy code from this push. * fix: specify out-of-the-box tile assignments Prevents placeholder applet showing on initial boot, for devices which use a mult-tile layout by default (VM-E290) * fix: verify settings version when loading * fix: wrong settings version * refactor: remove unimplemented argument from requestUpdate Specified whether or not to update "async", however the implementation was slightly broken, Applet::requestUpdate is only handled next time WindowManager::runOnce is called. This didn't allow code to actually await an update, which was misleading. * refactor: renaming Applet::render becomes Applet::onRender. Tile::displayedApplet becomes Tile::assignedApplet. New onRender method name allows us to move some of the pre and post render code from WindowManager into new Applet::render method, which will call onRender for us. * refactor: rendering Bit of a tidy-up. No intended change in behavior. * fix: optimize refresh times Shorter wait between retrying update if display was previously busy. Set anticipated update durations closer to observed values. No signifacant performance increase, but does decrease the amount of polling required. * feat: blocking update for E-Ink Option to wait for display update to complete before proceeding. Important when shutting down the device. * refactor: allow system applets to lock rendering Temporarily prevents other applets from rendering. * feat: boot and shutdown screens * feat: BluetoothStatus Adds a meshtastic::Status object which exposes the state of the Bluetooth connection. Intends to allow decoupling of UI code. * feat: Bluetooth pairing screen * fix: InkHUD defaults not honored * fix: random Bluetooth pin for NicheGraphics UIs * chore: button interrupts tested * fix: emoji reactions show as blank messages * fix: autoshow and notification triggered by outgoing message * feat: save InkHUD data before reboot Implemented with a new Observable. Previously, config and a few recent messages were saved on shutdown. These were lost if the device rebooted, for example when firmware settings were changed by a client. Now, the InkHUD config and recent messages saved on reboot, the same as during an intentional shutdown. * feat: imperial distances Controlled by the config.display.units setting * fix: hide features which are not yet implemented * refactor: faster rendering Previously, only tiles which requested update were re-rendered. Affected tiles had their region blanked before render, pixel by pixel. Benchmarking revealed that it is significantly faster to memset the framebuffer and redraw all tiles. * refactor: tile ownership Tiles and Applets now maintain a reciprocal link, which is enforced by asserts. Less confusing than the old situation, where an applet and a tile may disagree on their relationship. Empty tiles are now identified by a nullptr *Applet, instead of by having the placeholderApplet assigned. * fix: notifications and battery when menu open Do render notifications in front of menu; don't render battery icon in front of menu. * fix: simpler defaults Don't expose new users to multiplexed applets straight away: make them enable the feature for themselves. * fix: Inputs::TwoButton interrupts, when only one button in use * fix: ensure display update is complete when ESP32 enters light sleep Many panels power down automatically, but some require active intervention from us. If light sleep (ESP32) occurs during a display update, these panels could potentially remain powered on, applying voltage the pixels for an extended period of time, and potentially damaging the display. * fix: honor per-variant user tile limit Set as the default value for InkHUD::settings.userTiles.maxCount in nicheGraphics.h * feat: initial InkHUD support for Wireless Paper v1.1 and VM-E213 * refactor: Heard and Recents Applets Tidier code, significant speed boost. Possibly no noticable change in responsiveness, but rendering now spends much less time blocking execution, which is important for correction functioning of the other firmware components. * refactor: use a common pio base config Easier to make any future PlatformIO config changes * feat: tips Show information that we think the user might find helpful. Some info shown first boot only. Other info shown when / if relevant. * fix: text wrapping for '\n' Previously, the newline was honored, but the adojining word was not printed. * Decouple ButtonThread from sleep.cpp Reorganize sleep observables. Don't call ButtonThread methods inside doLightSleep. Instead, handle in class with new lightsleep Observables. * feat: BluetoothStatus Adds a meshtastic::Status object which exposes the state of the Bluetooth connection. Intends to allow decoupling of UI code. * feat: observable for reboot * refactor: Heltec VM-E290 installDefaultConfig * fix: random Bluetooth pin for NicheGraphics UIs * update device-ui: fix touch/crash issue while light sleep * Collect inkhud * fix: InkHUD shouldn't nag about timezone (#6040) * Guard eink drivers w/ MESHTASTIC_INCLUDE_NICHE_GRAPHICS * Case sensitive perhaps? * More case-sensitivity instances * Moar * RTC * Yet another case issue! * Sigh... * MUI: BT programming mode (#6046) * allow BT connection with disabled MUI * Update device-ui --------- Co-authored-by: Ben Meadors <benmmeadors@gmail.com> * MUI: fix nag timeout, disable BT programming mode for native (#6052) * allow BT connection with disabled MUI * Update device-ui * MUI: fix nag timeout default and remove programming mode for native --------- Co-authored-by: Ben Meadors <benmmeadors@gmail.com> * remove debuglog leftover * Wireless Paper: remove stray board_level = extra (#6060) Makes sure the InkHUD version gets build into the release zip * Fixed persistence stragglers from NodeDB / Device State divorce (#6059) * Increase `MAX_THREADS` for InkHUD variants with WiFi (#6064) * Licensed usage compliance (#6047) * Prevent psk and legacy admin channel on licensed mode * Move it * Consolidate warning strings * More holes * Device UI submodule bump * Prevent licensed users from rebroadcasting unlicensed traffic (#6068) * Prevent licensed users from rebroadcasting unlicensed traffic * Added method and enum to make user license status more clear * MUI: move UI initialization out of main.cpp and adding lightsleep observer + mutex (#6078) * added device-ui to lightSleep observers for handling graceful sleep; refactoring main.cpp * bump lib version * Update device-ui * unPhone TFT: include into build, enable SD card, increase PSRAM (#6082) * unPhone-tft: include into build, enable SD card, increase assigned PSRAM * lib update * Backup / migrate pub private keys when upgrading to new files in 2.6 (#6096) * Save a backup of pub/private keys before factory reset * Fix licensed mode warning * Unlock spi on else file doesn't exist * Update device-ui * Update protos and device-ui * [create-pull-request] automated change (#6129) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Proto * [create-pull-request] automated change (#6131) * Proto update for backup * [create-pull-request] automated change (#6133) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Update protobufs * Space * [create-pull-request] automated change (#6144) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Protos * [create-pull-request] automated change (#6152) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Updeet * device-ui lib update * fix channel OK button * device-lib update: fix settings panel -> no scrolling * device-ui lib: last minute update * defined(SENSECAP_INDICATOR) * MUI hot-fix pub/priv keys * MUI hot-fix username dialog * MUI: BT programming mode button * Update protobufs --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Co-authored-by: GUVWAF <thijs@havinga.eu> Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com> Co-authored-by: Tom Fifield <tom@tomfifield.net> Co-authored-by: mverch67 <manuel.verch@gmx.de> Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com> Co-authored-by: todd-herbert <herbert.todd@gmail.com> Co-authored-by: Jason Murray <15822260+scruplelesswizard@users.noreply.github.com> Co-authored-by: Jason Murray <jason@chaosaffe.io> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz> Co-authored-by: Austin <vidplace7@gmail.com> Co-authored-by: virgil <virgil.wang.cj@gmail.com> Co-authored-by: Mark Trevor Birss <markbirss@gmail.com> Co-authored-by: Kalle Lilja <15094562+ThatKalle@users.noreply.github.com> Co-authored-by: rcarteraz <robert.l.carter2@gmail.com>
1278 lines
42 KiB
C++
1278 lines
42 KiB
C++
#include "configuration.h"
|
|
#if !MESHTASTIC_EXCLUDE_GPS
|
|
#include "GPS.h"
|
|
#endif
|
|
#include "MeshRadio.h"
|
|
#include "MeshService.h"
|
|
#include "NodeDB.h"
|
|
#include "PowerFSM.h"
|
|
#include "PowerMon.h"
|
|
#include "ReliableRouter.h"
|
|
#include "airtime.h"
|
|
#include "buzz.h"
|
|
|
|
#include "FSCommon.h"
|
|
#include "Led.h"
|
|
#include "RTC.h"
|
|
#include "SPILock.h"
|
|
#include "Throttle.h"
|
|
#include "concurrency/OSThread.h"
|
|
#include "concurrency/Periodic.h"
|
|
#include "detect/ScanI2C.h"
|
|
#include "error.h"
|
|
#include "power.h"
|
|
|
|
#if !MESHTASTIC_EXCLUDE_I2C
|
|
#include "detect/ScanI2CTwoWire.h"
|
|
#include <Wire.h>
|
|
#endif
|
|
#include "detect/einkScan.h"
|
|
#include "graphics/RAKled.h"
|
|
#include "graphics/Screen.h"
|
|
#include "main.h"
|
|
#include "mesh/generated/meshtastic/config.pb.h"
|
|
#include "meshUtils.h"
|
|
#include "modules/Modules.h"
|
|
#include "shutdown.h"
|
|
#include "sleep.h"
|
|
#include "target_specific.h"
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#ifdef ARCH_ESP32
|
|
#include "freertosinc.h"
|
|
#if !MESHTASTIC_EXCLUDE_WEBSERVER
|
|
#include "mesh/http/WebServer.h"
|
|
#endif
|
|
#if !MESHTASTIC_EXCLUDE_BLUETOOTH
|
|
#include "nimble/NimbleBluetooth.h"
|
|
NimbleBluetooth *nimbleBluetooth = nullptr;
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef ARCH_NRF52
|
|
#include "NRF52Bluetooth.h"
|
|
NRF52Bluetooth *nrf52Bluetooth = nullptr;
|
|
#endif
|
|
|
|
#if HAS_WIFI
|
|
#include "mesh/api/WiFiServerAPI.h"
|
|
#include "mesh/wifi/WiFiAPClient.h"
|
|
#endif
|
|
|
|
#if HAS_ETHERNET
|
|
#include "mesh/api/ethServerAPI.h"
|
|
#include "mesh/eth/ethClient.h"
|
|
#endif
|
|
|
|
#if !MESHTASTIC_EXCLUDE_MQTT
|
|
#include "mqtt/MQTT.h"
|
|
#endif
|
|
|
|
#include "LLCC68Interface.h"
|
|
#include "LR1110Interface.h"
|
|
#include "LR1120Interface.h"
|
|
#include "LR1121Interface.h"
|
|
#include "RF95Interface.h"
|
|
#include "SX1262Interface.h"
|
|
#include "SX1268Interface.h"
|
|
#include "SX1280Interface.h"
|
|
#include "detect/LoRaRadioType.h"
|
|
|
|
#ifdef ARCH_STM32WL
|
|
#include "STM32WLE5JCInterface.h"
|
|
#endif
|
|
|
|
#if defined(ARCH_PORTDUINO)
|
|
#include "platform/portduino/SimRadio.h"
|
|
#endif
|
|
|
|
#ifdef ARCH_PORTDUINO
|
|
#include "linux/LinuxHardwareI2C.h"
|
|
#include "mesh/raspihttp/PiWebServer.h"
|
|
#include "platform/portduino/PortduinoGlue.h"
|
|
#include "platform/portduino/USBHal.h"
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <string>
|
|
#endif
|
|
|
|
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
|
|
#include "ButtonThread.h"
|
|
#endif
|
|
|
|
#include "AmbientLightingThread.h"
|
|
#include "PowerFSMThread.h"
|
|
|
|
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C
|
|
#include "motion/AccelerometerThread.h"
|
|
AccelerometerThread *accelerometerThread = nullptr;
|
|
#endif
|
|
|
|
#ifdef HAS_I2S
|
|
#include "AudioThread.h"
|
|
AudioThread *audioThread = nullptr;
|
|
#endif
|
|
|
|
#if HAS_TFT
|
|
extern void tftSetup(void);
|
|
#endif
|
|
|
|
#ifdef HAS_UDP_MULTICAST
|
|
#include "mesh/udp/UdpMulticastThread.h"
|
|
UdpMulticastThread *udpThread = nullptr;
|
|
#endif
|
|
|
|
#if defined(TCXO_OPTIONAL)
|
|
float tcxoVoltage = SX126X_DIO3_TCXO_VOLTAGE; // if TCXO is optional, put this here so it can be changed further down.
|
|
#endif
|
|
|
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
|
void setupNicheGraphics();
|
|
#include "nicheGraphics.h"
|
|
#endif
|
|
|
|
using namespace concurrency;
|
|
|
|
volatile static const char slipstreamTZString[] = {USERPREFS_TZ_STRING};
|
|
|
|
// We always create a screen object, but we only init it if we find the hardware
|
|
graphics::Screen *screen = nullptr;
|
|
|
|
// Global power status
|
|
meshtastic::PowerStatus *powerStatus = new meshtastic::PowerStatus();
|
|
|
|
// Global GPS status
|
|
meshtastic::GPSStatus *gpsStatus = new meshtastic::GPSStatus();
|
|
|
|
// Global Node status
|
|
meshtastic::NodeStatus *nodeStatus = new meshtastic::NodeStatus();
|
|
|
|
// Global Bluetooth status
|
|
meshtastic::BluetoothStatus *bluetoothStatus = new meshtastic::BluetoothStatus();
|
|
|
|
// Scan for I2C Devices
|
|
|
|
/// The I2C address of our display (if found)
|
|
ScanI2C::DeviceAddress screen_found = ScanI2C::ADDRESS_NONE;
|
|
|
|
// The I2C address of the cardkb or RAK14004 (if found)
|
|
ScanI2C::DeviceAddress cardkb_found = ScanI2C::ADDRESS_NONE;
|
|
// 0x02 for RAK14004, 0x00 for cardkb, 0x10 for T-Deck
|
|
uint8_t kb_model;
|
|
|
|
// The I2C address of the RTC Module (if found)
|
|
ScanI2C::DeviceAddress rtc_found = ScanI2C::ADDRESS_NONE;
|
|
// The I2C address of the Accelerometer (if found)
|
|
ScanI2C::DeviceAddress accelerometer_found = ScanI2C::ADDRESS_NONE;
|
|
// The I2C address of the RGB LED (if found)
|
|
ScanI2C::FoundDevice rgb_found = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ScanI2C::ADDRESS_NONE);
|
|
|
|
#ifdef T_WATCH_S3
|
|
Adafruit_DRV2605 drv;
|
|
#endif
|
|
|
|
// Global LoRa radio type
|
|
LoRaRadioType radioType = NO_RADIO;
|
|
|
|
bool isVibrating = false;
|
|
|
|
bool eink_found = true;
|
|
|
|
uint32_t serialSinceMsec;
|
|
bool pauseBluetoothLogging = false;
|
|
|
|
bool pmu_found;
|
|
|
|
#if !MESHTASTIC_EXCLUDE_I2C
|
|
// Array map of sensor types with i2c address and wire as we'll find in the i2c scan
|
|
std::pair<uint8_t, TwoWire *> nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1] = {};
|
|
#endif
|
|
|
|
Router *router = NULL; // Users of router don't care what sort of subclass implements that API
|
|
|
|
const char *firmware_version = optstr(APP_VERSION_SHORT);
|
|
|
|
const char *getDeviceName()
|
|
{
|
|
uint8_t dmac[6];
|
|
|
|
getMacAddr(dmac);
|
|
|
|
// Meshtastic_ab3c or Shortname_abcd
|
|
static char name[20];
|
|
snprintf(name, sizeof(name), "%02x%02x", dmac[4], dmac[5]);
|
|
// if the shortname exists and is NOT the new default of ab3c, use it for BLE name.
|
|
if (strcmp(owner.short_name, name) != 0) {
|
|
snprintf(name, sizeof(name), "%s_%02x%02x", owner.short_name, dmac[4], dmac[5]);
|
|
} else {
|
|
snprintf(name, sizeof(name), "Meshtastic_%02x%02x", dmac[4], dmac[5]);
|
|
}
|
|
return name;
|
|
}
|
|
|
|
static int32_t ledBlinker()
|
|
{
|
|
// Still set up the blinking (heartbeat) interval but skip code path below, so LED will blink if
|
|
// config.device.led_heartbeat_disabled is changed
|
|
if (config.device.led_heartbeat_disabled)
|
|
return 1000;
|
|
|
|
static bool ledOn;
|
|
ledOn ^= 1;
|
|
|
|
ledBlink.set(ledOn);
|
|
|
|
// have a very sparse duty cycle of LED being on, unless charging, then blink 0.5Hz square wave rate to indicate that
|
|
return powerStatus->getIsCharging() ? 1000 : (ledOn ? 1 : 1000);
|
|
}
|
|
|
|
uint32_t timeLastPowered = 0;
|
|
|
|
static Periodic *ledPeriodic;
|
|
static OSThread *powerFSMthread;
|
|
static OSThread *ambientLightingThread;
|
|
|
|
RadioInterface *rIf = NULL;
|
|
#ifdef ARCH_PORTDUINO
|
|
RadioLibHal *RadioLibHAL = NULL;
|
|
#endif
|
|
|
|
/**
|
|
* Some platforms (nrf52) might provide an alterate version that suppresses calling delay from sleep.
|
|
*/
|
|
__attribute__((weak, noinline)) bool loopCanSleep()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Weak empty variant initialization function.
|
|
// May be redefined by variant files.
|
|
void lateInitVariant() __attribute__((weak));
|
|
void lateInitVariant() {}
|
|
|
|
/**
|
|
* Print info as a structured log message (for automated log processing)
|
|
*/
|
|
void printInfo()
|
|
{
|
|
LOG_INFO("S:B:%d,%s", HW_VENDOR, optstr(APP_VERSION));
|
|
}
|
|
#ifndef PIO_UNIT_TESTING
|
|
void setup()
|
|
{
|
|
#if defined(T_DECK)
|
|
// GPIO10 manages all peripheral power supplies
|
|
// Turn on peripheral power immediately after MUC starts.
|
|
// If some boards are turned on late, ESP32 will reset due to low voltage.
|
|
// ESP32-C3(Keyboard) , MAX98357A(Audio Power Amplifier) ,
|
|
// TF Card , Display backlight(AW9364DNR) , AN48841B(Trackball) , ES7210(Decoder)
|
|
pinMode(KB_POWERON, OUTPUT);
|
|
digitalWrite(KB_POWERON, HIGH);
|
|
// T-Deck has all three SPI peripherals (TFT, SD, LoRa) attached to the same SPI bus
|
|
// We need to initialize all CS pins in advance otherwise there will be SPI communication issues
|
|
// e.g. when detecting the SD card
|
|
pinMode(LORA_CS, OUTPUT);
|
|
digitalWrite(LORA_CS, HIGH);
|
|
pinMode(SDCARD_CS, OUTPUT);
|
|
digitalWrite(SDCARD_CS, HIGH);
|
|
pinMode(TFT_CS, OUTPUT);
|
|
digitalWrite(TFT_CS, HIGH);
|
|
delay(100);
|
|
#endif
|
|
|
|
concurrency::hasBeenSetup = true;
|
|
#if ARCH_PORTDUINO
|
|
SPISettings spiSettings(settingsMap[spiSpeed], MSBFIRST, SPI_MODE0);
|
|
#else
|
|
SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
|
|
#endif
|
|
|
|
meshtastic_Config_DisplayConfig_OledType screen_model =
|
|
meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO;
|
|
OLEDDISPLAY_GEOMETRY screen_geometry = GEOMETRY_128_64;
|
|
|
|
#ifdef USE_SEGGER
|
|
auto mode = false ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM;
|
|
#ifdef NRF52840_XXAA
|
|
auto buflen = 4096; // this board has a fair amount of ram
|
|
#else
|
|
auto buflen = 256; // this board has a fair amount of ram
|
|
#endif
|
|
SEGGER_RTT_ConfigUpBuffer(SEGGER_STDOUT_CH, NULL, NULL, buflen, mode);
|
|
#endif
|
|
|
|
#ifdef DEBUG_PORT
|
|
consoleInit(); // Set serial baud rate and init our mesh console
|
|
#endif
|
|
|
|
#ifdef UNPHONE
|
|
unphone.printStore();
|
|
#endif
|
|
|
|
#if ARCH_PORTDUINO
|
|
struct timeval tv;
|
|
tv.tv_sec = time(NULL);
|
|
tv.tv_usec = 0;
|
|
perhapsSetRTC(RTCQualityNTP, &tv);
|
|
#endif
|
|
|
|
powerMonInit();
|
|
serialSinceMsec = millis();
|
|
|
|
LOG_INFO("\n\n//\\ E S H T /\\ S T / C\n");
|
|
|
|
initDeepSleep();
|
|
|
|
// power on peripherals
|
|
#if defined(PIN_POWER_EN)
|
|
pinMode(PIN_POWER_EN, OUTPUT);
|
|
digitalWrite(PIN_POWER_EN, HIGH);
|
|
// digitalWrite(PIN_POWER_EN1, INPUT);
|
|
#endif
|
|
|
|
#if defined(LORA_TCXO_GPIO)
|
|
pinMode(LORA_TCXO_GPIO, OUTPUT);
|
|
digitalWrite(LORA_TCXO_GPIO, HIGH);
|
|
#endif
|
|
|
|
#if defined(VEXT_ENABLE)
|
|
pinMode(VEXT_ENABLE, OUTPUT);
|
|
digitalWrite(VEXT_ENABLE, VEXT_ON_VALUE); // turn on the display power
|
|
#endif
|
|
|
|
#if defined(BIAS_T_ENABLE)
|
|
pinMode(BIAS_T_ENABLE, OUTPUT);
|
|
digitalWrite(BIAS_T_ENABLE, BIAS_T_VALUE); // turn on 5V for GPS Antenna
|
|
#endif
|
|
|
|
#if defined(VTFT_CTRL)
|
|
pinMode(VTFT_CTRL, OUTPUT);
|
|
digitalWrite(VTFT_CTRL, LOW);
|
|
#endif
|
|
|
|
#ifdef RESET_OLED
|
|
pinMode(RESET_OLED, OUTPUT);
|
|
digitalWrite(RESET_OLED, 1);
|
|
#endif
|
|
|
|
#ifdef SENSOR_POWER_CTRL_PIN
|
|
pinMode(SENSOR_POWER_CTRL_PIN, OUTPUT);
|
|
digitalWrite(SENSOR_POWER_CTRL_PIN, SENSOR_POWER_ON);
|
|
#endif
|
|
|
|
#ifdef SENSOR_GPS_CONFLICT
|
|
bool sensor_detected = false;
|
|
#endif
|
|
#ifdef PERIPHERAL_WARMUP_MS
|
|
// Some peripherals may require additional time to stabilize after power is connected
|
|
// e.g. I2C on Heltec Vision Master
|
|
LOG_INFO("Wait for peripherals to stabilize");
|
|
delay(PERIPHERAL_WARMUP_MS);
|
|
#endif
|
|
|
|
#ifdef BUTTON_PIN
|
|
#ifdef ARCH_ESP32
|
|
|
|
#if ESP_ARDUINO_VERSION_MAJOR >= 3
|
|
#ifdef BUTTON_NEED_PULLUP
|
|
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP);
|
|
#else
|
|
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
|
|
#endif
|
|
#else
|
|
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
|
|
#ifdef BUTTON_NEED_PULLUP
|
|
gpio_pullup_en((gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
|
|
delay(10);
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
initSPI();
|
|
|
|
OSThread::setup();
|
|
|
|
ledPeriodic = new Periodic("Blink", ledBlinker);
|
|
|
|
fsInit();
|
|
|
|
#if defined(_SEEED_XIAO_NRF52840_SENSE_H_)
|
|
|
|
pinMode(CHARGE_LED, INPUT); // sets to detect if charge LED is on or off to see if USB is plugged in
|
|
|
|
pinMode(HICHG, OUTPUT);
|
|
digitalWrite(HICHG, LOW); // 100 mA charging current if set to LOW and 50mA (actually about 20mA) if set to HIGH
|
|
|
|
pinMode(BAT_READ, OUTPUT);
|
|
digitalWrite(BAT_READ, LOW); // This is pin P0_14 = 14 and by pullling low to GND it provices path to read on pin 32 (P0,31)
|
|
// PIN_VBAT the voltage from divider on XIAO board
|
|
|
|
#endif
|
|
|
|
#if !MESHTASTIC_EXCLUDE_I2C
|
|
#if defined(I2C_SDA1) && defined(ARCH_RP2040)
|
|
Wire1.setSDA(I2C_SDA1);
|
|
Wire1.setSCL(I2C_SCL1);
|
|
Wire1.begin();
|
|
#elif defined(I2C_SDA1) && !defined(ARCH_RP2040)
|
|
Wire1.begin(I2C_SDA1, I2C_SCL1);
|
|
#elif WIRE_INTERFACES_COUNT == 2
|
|
Wire1.begin();
|
|
#endif
|
|
|
|
#if defined(I2C_SDA) && defined(ARCH_RP2040)
|
|
Wire.setSDA(I2C_SDA);
|
|
Wire.setSCL(I2C_SCL);
|
|
Wire.begin();
|
|
#elif defined(I2C_SDA) && !defined(ARCH_RP2040)
|
|
Wire.begin(I2C_SDA, I2C_SCL);
|
|
#elif defined(ARCH_PORTDUINO)
|
|
if (settingsStrings[i2cdev] != "") {
|
|
LOG_INFO("Use %s as I2C device", settingsStrings[i2cdev].c_str());
|
|
Wire.begin(settingsStrings[i2cdev].c_str());
|
|
} else {
|
|
LOG_INFO("No I2C device configured, Skip");
|
|
}
|
|
#elif HAS_WIRE
|
|
Wire.begin();
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef PIN_LCD_RESET
|
|
// FIXME - move this someplace better, LCD is at address 0x3F
|
|
pinMode(PIN_LCD_RESET, OUTPUT);
|
|
digitalWrite(PIN_LCD_RESET, 0);
|
|
delay(1);
|
|
digitalWrite(PIN_LCD_RESET, 1);
|
|
delay(1);
|
|
#endif
|
|
|
|
#ifdef AQ_SET_PIN
|
|
// RAK-12039 set pin for Air quality sensor. Detectable on I2C after ~3 seconds, so we need to rescan later
|
|
pinMode(AQ_SET_PIN, OUTPUT);
|
|
digitalWrite(AQ_SET_PIN, HIGH);
|
|
#endif
|
|
|
|
#if HAS_TFT
|
|
tftSetup();
|
|
#endif
|
|
|
|
// Currently only the tbeam has a PMU
|
|
// PMU initialization needs to be placed before i2c scanning
|
|
power = new Power();
|
|
power->setStatusHandler(powerStatus);
|
|
powerStatus->observe(&power->newStatus);
|
|
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
|
|
|
|
#if !MESHTASTIC_EXCLUDE_I2C
|
|
// We need to scan here to decide if we have a screen for nodeDB.init() and because power has been applied to
|
|
// accessories
|
|
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
|
#if HAS_WIRE
|
|
LOG_INFO("Scan for i2c devices");
|
|
#endif
|
|
|
|
#if defined(I2C_SDA1) && defined(ARCH_RP2040)
|
|
Wire1.setSDA(I2C_SDA1);
|
|
Wire1.setSCL(I2C_SCL1);
|
|
Wire1.begin();
|
|
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
|
|
#elif defined(I2C_SDA1) && !defined(ARCH_RP2040)
|
|
Wire1.begin(I2C_SDA1, I2C_SCL1);
|
|
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
|
|
#elif defined(NRF52840_XXAA) && (WIRE_INTERFACES_COUNT == 2)
|
|
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1);
|
|
#endif
|
|
|
|
#if defined(I2C_SDA) && defined(ARCH_RP2040)
|
|
Wire.setSDA(I2C_SDA);
|
|
Wire.setSCL(I2C_SCL);
|
|
Wire.begin();
|
|
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
|
|
#elif defined(I2C_SDA) && !defined(ARCH_RP2040)
|
|
Wire.begin(I2C_SDA, I2C_SCL);
|
|
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
|
|
#elif defined(ARCH_PORTDUINO)
|
|
if (settingsStrings[i2cdev] != "") {
|
|
LOG_INFO("Scan for i2c devices");
|
|
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
|
|
}
|
|
#elif HAS_WIRE
|
|
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
|
|
#endif
|
|
|
|
auto i2cCount = i2cScanner->countDevices();
|
|
if (i2cCount == 0) {
|
|
LOG_INFO("No I2C devices found");
|
|
} else {
|
|
LOG_INFO("%i I2C devices found", i2cCount);
|
|
#ifdef SENSOR_GPS_CONFLICT
|
|
sensor_detected = true;
|
|
#endif
|
|
}
|
|
|
|
#ifdef ARCH_ESP32
|
|
// Don't init display if we don't have one or we are waking headless due to a timer event
|
|
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) {
|
|
LOG_DEBUG("suppress screen wake because this is a headless timer wakeup");
|
|
i2cScanner->setSuppressScreen();
|
|
}
|
|
#endif
|
|
|
|
auto screenInfo = i2cScanner->firstScreen();
|
|
screen_found = screenInfo.type != ScanI2C::DeviceType::NONE ? screenInfo.address : ScanI2C::ADDRESS_NONE;
|
|
|
|
if (screen_found.port != ScanI2C::I2CPort::NO_I2C) {
|
|
switch (screenInfo.type) {
|
|
case ScanI2C::DeviceType::SCREEN_SH1106:
|
|
screen_model = meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_SH1106;
|
|
break;
|
|
case ScanI2C::DeviceType::SCREEN_SSD1306:
|
|
screen_model = meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_SSD1306;
|
|
break;
|
|
case ScanI2C::DeviceType::SCREEN_ST7567:
|
|
case ScanI2C::DeviceType::SCREEN_UNKNOWN:
|
|
default:
|
|
screen_model = meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO;
|
|
}
|
|
}
|
|
|
|
#define UPDATE_FROM_SCANNER(FIND_FN)
|
|
|
|
auto rtc_info = i2cScanner->firstRTC();
|
|
rtc_found = rtc_info.type != ScanI2C::DeviceType::NONE ? rtc_info.address : rtc_found;
|
|
|
|
auto kb_info = i2cScanner->firstKeyboard();
|
|
|
|
if (kb_info.type != ScanI2C::DeviceType::NONE) {
|
|
cardkb_found = kb_info.address;
|
|
switch (kb_info.type) {
|
|
case ScanI2C::DeviceType::RAK14004:
|
|
kb_model = 0x02;
|
|
break;
|
|
case ScanI2C::DeviceType::CARDKB:
|
|
kb_model = 0x00;
|
|
break;
|
|
case ScanI2C::DeviceType::TDECKKB:
|
|
// assign an arbitrary value to distinguish from other models
|
|
kb_model = 0x10;
|
|
break;
|
|
case ScanI2C::DeviceType::BBQ10KB:
|
|
// assign an arbitrary value to distinguish from other models
|
|
kb_model = 0x11;
|
|
break;
|
|
case ScanI2C::DeviceType::MPR121KB:
|
|
// assign an arbitrary value to distinguish from other models
|
|
kb_model = 0x37;
|
|
break;
|
|
default:
|
|
// use this as default since it's also just zero
|
|
LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00", kb_info.type);
|
|
kb_model = 0x00;
|
|
}
|
|
}
|
|
|
|
pmu_found = i2cScanner->exists(ScanI2C::DeviceType::PMU_AXP192_AXP2101);
|
|
|
|
/*
|
|
* There are a bunch of sensors that have no further logic than to be found and stuffed into the
|
|
* nodeTelemetrySensorsMap singleton. This wraps that logic in a temporary scope to declare the temporary field
|
|
* "found".
|
|
*/
|
|
|
|
// Only one supported RGB LED currently
|
|
#ifdef HAS_NCP5623
|
|
rgb_found = i2cScanner->find(ScanI2C::DeviceType::NCP5623);
|
|
#endif
|
|
|
|
#ifdef HAS_TPS65233
|
|
// TPS65233 is a power management IC for satellite modems, used in the Dreamcatcher
|
|
// We are switching it off here since we don't use an LNB.
|
|
if (i2cScanner->exists(ScanI2C::DeviceType::TPS65233)) {
|
|
Wire.beginTransmission(TPS65233_ADDR);
|
|
Wire.write(0); // Register 0
|
|
Wire.write(128); // Turn off the LNB power, keep I2C Control enabled
|
|
Wire.endTransmission();
|
|
Wire.beginTransmission(TPS65233_ADDR);
|
|
Wire.write(1); // Register 1
|
|
Wire.write(0); // Turn off Tone Generator 22kHz
|
|
Wire.endTransmission();
|
|
}
|
|
#endif
|
|
|
|
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
|
auto acc_info = i2cScanner->firstAccelerometer();
|
|
accelerometer_found = acc_info.type != ScanI2C::DeviceType::NONE ? acc_info.address : accelerometer_found;
|
|
LOG_DEBUG("acc_info = %i", acc_info.type);
|
|
#endif
|
|
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_3XX, meshtastic_TelemetrySensorType_BMP3XX);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_085, meshtastic_TelemetrySensorType_BMP085);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA226, meshtastic_TelemetrySensorType_INA226);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX17048, meshtastic_TelemetrySensorType_MAX17048);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::LPS22HB, meshtastic_TelemetrySensorType_LPS22);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMC6310, meshtastic_TelemetrySensorType_QMC6310);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::HMC5883L, meshtastic_TelemetrySensorType_QMC5883L);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RCWL9620, meshtastic_TelemetrySensorType_RCWL9620);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::VEML7700, meshtastic_TelemetrySensorType_VEML7700);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::TSL2591, meshtastic_TelemetrySensorType_TSL25911FN);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::OPT3001, meshtastic_TelemetrySensorType_OPT3001);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MLX90632, meshtastic_TelemetrySensorType_MLX90632);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MLX90614, meshtastic_TelemetrySensorType_MLX90614);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHT4X, meshtastic_TelemetrySensorType_SHT4X);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::AHT10, meshtastic_TelemetrySensorType_AHT10);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::ICM20948, meshtastic_TelemetrySensorType_ICM20948);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX30102, meshtastic_TelemetrySensorType_MAX30102);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::CGRADSENS, meshtastic_TelemetrySensorType_RADSENS);
|
|
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DFROBOT_RAIN, meshtastic_TelemetrySensorType_DFROBOT_RAIN);
|
|
|
|
i2cScanner.reset();
|
|
#endif
|
|
|
|
#ifdef HAS_SDCARD
|
|
setupSDCard();
|
|
#endif
|
|
|
|
// LED init
|
|
|
|
#ifdef LED_PIN
|
|
pinMode(LED_PIN, OUTPUT);
|
|
digitalWrite(LED_PIN, LED_STATE_ON); // turn on for now
|
|
#endif
|
|
|
|
// Hello
|
|
printInfo();
|
|
#ifdef BUILD_EPOCH
|
|
LOG_INFO("Build timestamp: %ld", BUILD_EPOCH);
|
|
#endif
|
|
|
|
#ifdef ARCH_ESP32
|
|
esp32Setup();
|
|
#endif
|
|
|
|
#ifdef ARCH_NRF52
|
|
nrf52Setup();
|
|
#endif
|
|
|
|
#ifdef ARCH_RP2040
|
|
rp2040Setup();
|
|
#endif
|
|
|
|
// We do this as early as possible because this loads preferences from flash
|
|
// but we need to do this after main cpu init (esp32setup), because we need the random seed set
|
|
nodeDB = new NodeDB;
|
|
|
|
// If we're taking on the repeater role, use NextHopRouter and turn off 3V3_S rail because peripherals are not needed
|
|
if (config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) {
|
|
router = new NextHopRouter();
|
|
#ifdef PIN_3V3_EN
|
|
digitalWrite(PIN_3V3_EN, LOW);
|
|
#endif
|
|
} else
|
|
router = new ReliableRouter();
|
|
|
|
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
|
|
// Buttons. Moved here cause we need NodeDB to be initialized
|
|
buttonThread = new ButtonThread();
|
|
#endif
|
|
|
|
// only play start melody when role is not tracker or sensor
|
|
if (config.power.is_power_saving == true &&
|
|
IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TRACKER,
|
|
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER, meshtastic_Config_DeviceConfig_Role_SENSOR))
|
|
LOG_DEBUG("Tracker/Sensor: Skip start melody");
|
|
else
|
|
playStartMelody();
|
|
|
|
// fixed screen override?
|
|
if (config.display.oled != meshtastic_Config_DisplayConfig_OledType_OLED_AUTO)
|
|
screen_model = config.display.oled;
|
|
|
|
#if defined(USE_SH1107)
|
|
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128
|
|
screen_geometry = GEOMETRY_128_128;
|
|
#endif
|
|
|
|
#if defined(USE_SH1107_128_64)
|
|
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // keep dimension of 128x64
|
|
#endif
|
|
|
|
#if !MESHTASTIC_EXCLUDE_I2C
|
|
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
|
if (acc_info.type != ScanI2C::DeviceType::NONE) {
|
|
accelerometerThread = new AccelerometerThread(acc_info.type);
|
|
}
|
|
#endif
|
|
|
|
#if defined(HAS_NEOPIXEL) || defined(UNPHONE) || defined(RGBLED_RED)
|
|
ambientLightingThread = new AmbientLightingThread(ScanI2C::DeviceType::NONE);
|
|
#elif !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
|
if (rgb_found.type != ScanI2C::DeviceType::NONE) {
|
|
ambientLightingThread = new AmbientLightingThread(rgb_found.type);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef T_WATCH_S3
|
|
drv.begin();
|
|
drv.selectLibrary(1);
|
|
// I2C trigger by sending 'go' command
|
|
drv.setMode(DRV2605_MODE_INTTRIG);
|
|
#endif
|
|
|
|
// Init our SPI controller (must be before screen and lora)
|
|
#ifdef ARCH_RP2040
|
|
#ifdef HW_SPI1_DEVICE
|
|
SPI1.setSCK(LORA_SCK);
|
|
SPI1.setTX(LORA_MOSI);
|
|
SPI1.setRX(LORA_MISO);
|
|
pinMode(LORA_CS, OUTPUT);
|
|
digitalWrite(LORA_CS, HIGH);
|
|
SPI1.begin(false);
|
|
#else // HW_SPI1_DEVICE
|
|
SPI.setSCK(LORA_SCK);
|
|
SPI.setTX(LORA_MOSI);
|
|
SPI.setRX(LORA_MISO);
|
|
SPI.begin(false);
|
|
#endif // HW_SPI1_DEVICE
|
|
#elif ARCH_PORTDUINO
|
|
if (settingsStrings[spidev] != "ch341") {
|
|
SPI.begin();
|
|
}
|
|
#elif !defined(ARCH_ESP32) // ARCH_RP2040
|
|
SPI.begin();
|
|
#else
|
|
// ESP32
|
|
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
|
LOG_DEBUG("SPI.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
|
SPI.setFrequency(4000000);
|
|
#endif
|
|
|
|
// Initialize the screen first so we can show the logo while we start up everything else.
|
|
#if HAS_SCREEN
|
|
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
|
|
#endif
|
|
// setup TZ prior to time actions.
|
|
#if !MESHTASTIC_EXCLUDE_TZ
|
|
LOG_DEBUG("Use compiled/slipstreamed %s", slipstreamTZString); // important, removing this clobbers our magic string
|
|
if (*config.device.tzdef && config.device.tzdef[0] != 0) {
|
|
LOG_DEBUG("Saved TZ: %s ", config.device.tzdef);
|
|
setenv("TZ", config.device.tzdef, 1);
|
|
} else {
|
|
if (strncmp((const char *)slipstreamTZString, "tzpl", 4) == 0) {
|
|
setenv("TZ", "GMT0", 1);
|
|
} else {
|
|
setenv("TZ", (const char *)slipstreamTZString, 1);
|
|
strcpy(config.device.tzdef, (const char *)slipstreamTZString);
|
|
}
|
|
}
|
|
tzset();
|
|
LOG_DEBUG("Set Timezone to %s", getenv("TZ"));
|
|
#endif
|
|
|
|
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
|
|
|
|
#if !MESHTASTIC_EXCLUDE_GPS
|
|
// If we're taking on the repeater role, ignore GPS
|
|
#ifdef SENSOR_GPS_CONFLICT
|
|
if (sensor_detected == false) {
|
|
#endif
|
|
if (HAS_GPS) {
|
|
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER &&
|
|
config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT) {
|
|
gps = GPS::createGps();
|
|
if (gps) {
|
|
gpsStatus->observe(&gps->newStatus);
|
|
} else {
|
|
LOG_DEBUG("Run without GPS");
|
|
}
|
|
}
|
|
}
|
|
#ifdef SENSOR_GPS_CONFLICT
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
nodeStatus->observe(&nodeDB->newStatus);
|
|
|
|
#ifdef HAS_I2S
|
|
LOG_DEBUG("Start audio thread");
|
|
audioThread = new AudioThread();
|
|
#endif
|
|
|
|
#ifdef HAS_UDP_MULTICAST
|
|
LOG_DEBUG("Start multicast thread");
|
|
udpThread = new UdpMulticastThread();
|
|
#endif
|
|
service = new MeshService();
|
|
service->init();
|
|
|
|
// Now that the mesh service is created, create any modules
|
|
setupModules();
|
|
|
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
|
// After modules are setup, so we can observe modules
|
|
setupNicheGraphics();
|
|
#endif
|
|
|
|
#ifdef LED_PIN
|
|
// Turn LED off after boot, if heartbeat by config
|
|
if (config.device.led_heartbeat_disabled)
|
|
digitalWrite(LED_PIN, HIGH ^ LED_STATE_ON);
|
|
#endif
|
|
|
|
// Do this after service.init (because that clears error_code)
|
|
#ifdef HAS_PMU
|
|
if (!pmu_found)
|
|
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_NO_AXP192); // Record a hardware fault for missing hardware
|
|
#endif
|
|
|
|
#if !MESHTASTIC_EXCLUDE_I2C
|
|
// Don't call screen setup until after nodedb is setup (because we need
|
|
// the current region name)
|
|
#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)
|
|
screen->setup();
|
|
#elif defined(ARCH_PORTDUINO)
|
|
if (screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) {
|
|
screen->setup();
|
|
}
|
|
#else
|
|
if (screen_found.port != ScanI2C::I2CPort::NO_I2C)
|
|
screen->setup();
|
|
#endif
|
|
#endif
|
|
|
|
screen->print("Started...\n");
|
|
|
|
#ifdef PIN_PWR_DELAY_MS
|
|
// This may be required to give the peripherals time to power up.
|
|
delay(PIN_PWR_DELAY_MS);
|
|
#endif
|
|
|
|
#ifdef ARCH_PORTDUINO
|
|
const struct {
|
|
configNames cfgName;
|
|
std::string strName;
|
|
} loraModules[] = {{use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"}, {use_sx1280, "sx1280"},
|
|
{use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
|
|
// as one can't use a function pointer to the class constructor:
|
|
auto loraModuleInterface = [](configNames cfgName, LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq,
|
|
RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy) {
|
|
switch (cfgName) {
|
|
case use_rf95:
|
|
return (RadioInterface *)new RF95Interface(hal, cs, irq, rst, busy);
|
|
case use_sx1262:
|
|
return (RadioInterface *)new SX1262Interface(hal, cs, irq, rst, busy);
|
|
case use_sx1268:
|
|
return (RadioInterface *)new SX1268Interface(hal, cs, irq, rst, busy);
|
|
case use_sx1280:
|
|
return (RadioInterface *)new SX1280Interface(hal, cs, irq, rst, busy);
|
|
case use_lr1110:
|
|
return (RadioInterface *)new LR1110Interface(hal, cs, irq, rst, busy);
|
|
case use_lr1120:
|
|
return (RadioInterface *)new LR1120Interface(hal, cs, irq, rst, busy);
|
|
case use_lr1121:
|
|
return (RadioInterface *)new LR1121Interface(hal, cs, irq, rst, busy);
|
|
case use_llcc68:
|
|
return (RadioInterface *)new LLCC68Interface(hal, cs, irq, rst, busy);
|
|
default:
|
|
assert(0); // shouldn't happen
|
|
return (RadioInterface *)nullptr;
|
|
}
|
|
};
|
|
for (auto &loraModule : loraModules) {
|
|
if (settingsMap[loraModule.cfgName] && !rIf) {
|
|
LOG_DEBUG("Activate %s radio on SPI port %s", loraModule.strName.c_str(), settingsStrings[spidev].c_str());
|
|
if (settingsStrings[spidev] == "ch341") {
|
|
RadioLibHAL = ch341Hal;
|
|
} else {
|
|
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
|
}
|
|
rIf = loraModuleInterface(loraModule.cfgName, (LockingArduinoHal *)RadioLibHAL, settingsMap[cs_pin],
|
|
settingsMap[irq_pin], settingsMap[reset_pin], settingsMap[busy_pin]);
|
|
if (!rIf->init()) {
|
|
LOG_WARN("No %s radio", loraModule.strName.c_str());
|
|
delete rIf;
|
|
rIf = NULL;
|
|
exit(EXIT_FAILURE);
|
|
} else {
|
|
LOG_INFO("%s init success", loraModule.strName.c_str());
|
|
}
|
|
}
|
|
}
|
|
#elif defined(HW_SPI1_DEVICE)
|
|
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI1, spiSettings);
|
|
#else // HW_SPI1_DEVICE
|
|
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
|
#endif
|
|
|
|
// radio init MUST BE AFTER service.init, so we have our radio config settings (from nodedb init)
|
|
#if defined(USE_STM32WLx)
|
|
if (!rIf) {
|
|
rIf = new STM32WLE5JCInterface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
|
|
if (!rIf->init()) {
|
|
LOG_WARN("No STM32WL radio");
|
|
delete rIf;
|
|
rIf = NULL;
|
|
} else {
|
|
LOG_INFO("STM32WL init success");
|
|
radioType = STM32WLx_RADIO;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(ARCH_PORTDUINO)
|
|
if (!rIf) {
|
|
rIf = new SimRadio;
|
|
if (!rIf->init()) {
|
|
LOG_WARN("No simulated radio");
|
|
delete rIf;
|
|
rIf = NULL;
|
|
} else {
|
|
LOG_INFO("Use SIMULATED radio!");
|
|
radioType = SIM_RADIO;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(RF95_IRQ) && RADIOLIB_EXCLUDE_SX127X != 1
|
|
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
|
|
rIf = new RF95Interface(RadioLibHAL, LORA_CS, RF95_IRQ, RF95_RESET, RF95_DIO1);
|
|
if (!rIf->init()) {
|
|
LOG_WARN("No RF95 radio");
|
|
delete rIf;
|
|
rIf = NULL;
|
|
} else {
|
|
LOG_INFO("RF95 init success");
|
|
radioType = RF95_RADIO;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(USE_SX1262) && !defined(ARCH_PORTDUINO) && !defined(TCXO_OPTIONAL) && RADIOLIB_EXCLUDE_SX126X != 1
|
|
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
|
|
auto *sxIf = new SX1262Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
|
|
#ifdef SX126X_DIO3_TCXO_VOLTAGE
|
|
sxIf->setTCXOVoltage(SX126X_DIO3_TCXO_VOLTAGE);
|
|
#endif
|
|
if (!sxIf->init()) {
|
|
LOG_WARN("No SX1262 radio");
|
|
delete sxIf;
|
|
rIf = NULL;
|
|
} else {
|
|
LOG_INFO("SX1262 init success");
|
|
rIf = sxIf;
|
|
radioType = SX1262_RADIO;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(USE_SX1262) && !defined(ARCH_PORTDUINO) && defined(TCXO_OPTIONAL)
|
|
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
|
|
// try using the specified TCXO voltage
|
|
auto *sxIf = new SX1262Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
|
|
sxIf->setTCXOVoltage(SX126X_DIO3_TCXO_VOLTAGE);
|
|
if (!sxIf->init()) {
|
|
LOG_WARN("No SX1262 radio with TCXO, Vref %fV", SX126X_DIO3_TCXO_VOLTAGE);
|
|
delete sxIf;
|
|
rIf = NULL;
|
|
} else {
|
|
LOG_INFO("SX1262 init success, TCXO, Vref %fV", SX126X_DIO3_TCXO_VOLTAGE);
|
|
rIf = sxIf;
|
|
radioType = SX1262_RADIO;
|
|
}
|
|
}
|
|
|
|
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
|
|
// If specified TCXO voltage fails, attempt to use DIO3 as a reference instead
|
|
rIf = new SX1262Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
|
|
if (!rIf->init()) {
|
|
LOG_WARN("No SX1262 radio with XTAL, Vref 0.0V");
|
|
delete rIf;
|
|
rIf = NULL;
|
|
} else {
|
|
LOG_INFO("SX1262 init success, XTAL, Vref 0.0V");
|
|
radioType = SX1262_RADIO;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(USE_SX1268)
|
|
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
|
|
rIf = new SX1268Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
|
|
if (!rIf->init()) {
|
|
LOG_WARN("No SX1268 radio");
|
|
delete rIf;
|
|
rIf = NULL;
|
|
} else {
|
|
LOG_INFO("SX1268 init success");
|
|
radioType = SX1268_RADIO;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(USE_LLCC68)
|
|
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
|
|
rIf = new LLCC68Interface(RadioLibHAL, SX126X_CS, SX126X_DIO1, SX126X_RESET, SX126X_BUSY);
|
|
if (!rIf->init()) {
|
|
LOG_WARN("No LLCC68 radio");
|
|
delete rIf;
|
|
rIf = NULL;
|
|
} else {
|
|
LOG_INFO("LLCC68 init success");
|
|
radioType = LLCC68_RADIO;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(USE_LR1110) && RADIOLIB_EXCLUDE_LR11X0 != 1
|
|
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
|
|
rIf = new LR1110Interface(RadioLibHAL, LR1110_SPI_NSS_PIN, LR1110_IRQ_PIN, LR1110_NRESET_PIN, LR1110_BUSY_PIN);
|
|
if (!rIf->init()) {
|
|
LOG_WARN("No LR1110 radio");
|
|
delete rIf;
|
|
rIf = NULL;
|
|
} else {
|
|
LOG_INFO("LR1110 init success");
|
|
radioType = LR1110_RADIO;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(USE_LR1120) && RADIOLIB_EXCLUDE_LR11X0 != 1
|
|
if (!rIf) {
|
|
rIf = new LR1120Interface(RadioLibHAL, LR1120_SPI_NSS_PIN, LR1120_IRQ_PIN, LR1120_NRESET_PIN, LR1120_BUSY_PIN);
|
|
if (!rIf->init()) {
|
|
LOG_WARN("No LR1120 radio");
|
|
delete rIf;
|
|
rIf = NULL;
|
|
} else {
|
|
LOG_INFO("LR1120 init success");
|
|
radioType = LR1120_RADIO;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(USE_LR1121) && RADIOLIB_EXCLUDE_LR11X0 != 1
|
|
if (!rIf) {
|
|
rIf = new LR1121Interface(RadioLibHAL, LR1121_SPI_NSS_PIN, LR1121_IRQ_PIN, LR1121_NRESET_PIN, LR1121_BUSY_PIN);
|
|
if (!rIf->init()) {
|
|
LOG_WARN("No LR1121 radio");
|
|
delete rIf;
|
|
rIf = NULL;
|
|
} else {
|
|
LOG_INFO("LR1121 init success");
|
|
radioType = LR1121_RADIO;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(USE_SX1280) && RADIOLIB_EXCLUDE_SX128X != 1
|
|
if (!rIf) {
|
|
rIf = new SX1280Interface(RadioLibHAL, SX128X_CS, SX128X_DIO1, SX128X_RESET, SX128X_BUSY);
|
|
if (!rIf->init()) {
|
|
LOG_WARN("No SX1280 radio");
|
|
delete rIf;
|
|
rIf = NULL;
|
|
} else {
|
|
LOG_INFO("SX1280 init success");
|
|
radioType = SX1280_RADIO;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// check if the radio chip matches the selected region
|
|
if ((config.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24) && (!rIf->wideLora())) {
|
|
LOG_WARN("LoRa chip does not support 2.4GHz. Revert to unset");
|
|
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET;
|
|
nodeDB->saveToDisk(SEGMENT_CONFIG);
|
|
if (!rIf->reconfigure()) {
|
|
LOG_WARN("Reconfigure failed, rebooting");
|
|
screen->startAlert("Rebooting...");
|
|
rebootAtMsec = millis() + 5000;
|
|
}
|
|
}
|
|
|
|
lateInitVariant(); // Do board specific init (see extra_variants/README.md for documentation)
|
|
|
|
#if !MESHTASTIC_EXCLUDE_MQTT
|
|
mqttInit();
|
|
#endif
|
|
|
|
#ifdef RF95_FAN_EN
|
|
// Ability to disable FAN if PIN has been set with RF95_FAN_EN.
|
|
// Make sure LoRa has been started before disabling FAN.
|
|
if (config.lora.pa_fan_disabled)
|
|
digitalWrite(RF95_FAN_EN, LOW ^ 0);
|
|
#endif
|
|
|
|
#ifndef ARCH_PORTDUINO
|
|
|
|
// Initialize Wifi
|
|
#if HAS_WIFI
|
|
initWifi();
|
|
#endif
|
|
|
|
#if HAS_ETHERNET
|
|
// Initialize Ethernet
|
|
initEthernet();
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WEBSERVER
|
|
// Start web server thread.
|
|
webServerThread = new WebServerThread();
|
|
#endif
|
|
|
|
#ifdef ARCH_PORTDUINO
|
|
#if __has_include(<ulfius.h>)
|
|
if (settingsMap[webserverport] != -1) {
|
|
piwebServerThread = new PiWebServerThread();
|
|
std::atexit([] { delete piwebServerThread; });
|
|
}
|
|
#endif
|
|
initApiServer(TCPPort);
|
|
#endif
|
|
|
|
// Start airtime logger thread.
|
|
airTime = new AirTime();
|
|
|
|
if (!rIf)
|
|
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_NO_RADIO);
|
|
else {
|
|
router->addInterface(rIf);
|
|
|
|
// Log bit rate to debug output
|
|
LOG_DEBUG("LoRA bitrate = %f bytes / sec", (float(meshtastic_Constants_DATA_PAYLOAD_LEN) /
|
|
(float(rIf->getPacketTime(meshtastic_Constants_DATA_PAYLOAD_LEN)))) *
|
|
1000);
|
|
}
|
|
|
|
// This must be _after_ service.init because we need our preferences loaded from flash to have proper timeout values
|
|
PowerFSM_setup(); // we will transition to ON in a couple of seconds, FIXME, only do this for cold boots, not waking from SDS
|
|
powerFSMthread = new PowerFSMThread();
|
|
|
|
#if !HAS_TFT
|
|
setCPUFast(false); // 80MHz is fine for our slow peripherals
|
|
#endif
|
|
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
LOG_DEBUG("Free heap : %7d bytes", ESP.getFreeHeap());
|
|
LOG_DEBUG("Free PSRAM : %7d bytes", ESP.getFreePsram());
|
|
#endif
|
|
}
|
|
#endif
|
|
uint32_t rebootAtMsec; // If not zero we will reboot at this time (used to reboot shortly after the update completes)
|
|
uint32_t shutdownAtMsec; // If not zero we will shutdown at this time (used to shutdown from python or mobile client)
|
|
|
|
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
|
|
// This will suppress the current delay and instead try to run ASAP.
|
|
bool runASAP;
|
|
|
|
extern meshtastic_DeviceMetadata getDeviceMetadata()
|
|
{
|
|
meshtastic_DeviceMetadata deviceMetadata;
|
|
strncpy(deviceMetadata.firmware_version, optstr(APP_VERSION), sizeof(deviceMetadata.firmware_version));
|
|
deviceMetadata.device_state_version = DEVICESTATE_CUR_VER;
|
|
deviceMetadata.canShutdown = pmu_found || HAS_CPU_SHUTDOWN;
|
|
deviceMetadata.hasBluetooth = HAS_BLUETOOTH;
|
|
deviceMetadata.hasWifi = HAS_WIFI;
|
|
deviceMetadata.hasEthernet = HAS_ETHERNET;
|
|
deviceMetadata.role = config.device.role;
|
|
deviceMetadata.position_flags = config.position.position_flags;
|
|
deviceMetadata.hw_model = HW_VENDOR;
|
|
deviceMetadata.hasRemoteHardware = moduleConfig.remote_hardware.enabled;
|
|
deviceMetadata.excluded_modules = meshtastic_ExcludedModules_EXCLUDED_NONE;
|
|
#if MESHTASTIC_EXCLUDE_REMOTEHARDWARE
|
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_REMOTEHARDWARE_CONFIG;
|
|
#endif
|
|
#if MESHTASTIC_EXCLUDE_AUDIO
|
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_AUDIO_CONFIG;
|
|
#endif
|
|
#if !HAS_SCREEN || NO_EXT_GPIO
|
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_CANNEDMSG_CONFIG | meshtastic_ExcludedModules_EXTNOTIF_CONFIG;
|
|
#endif
|
|
// Only edge case here is if we apply this a device with built in Accelerometer and want to detect interrupts
|
|
// We'll have to macro guard against those targets potentially
|
|
#if NO_EXT_GPIO
|
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_DETECTIONSENSOR_CONFIG;
|
|
#endif
|
|
// If we don't have any GPIO and we don't have GPS, no purpose in having serial config
|
|
#if NO_EXT_GPIO && NO_GPS
|
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_SERIAL_CONFIG;
|
|
#endif
|
|
#ifndef ARCH_ESP32
|
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_PAXCOUNTER_CONFIG;
|
|
#endif
|
|
#if !defined(HAS_NCP5623) && !defined(RGBLED_RED) && !defined(HAS_NEOPIXEL) && !defined(UNPHONE) && !RAK_4631
|
|
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_AMBIENTLIGHTING_CONFIG;
|
|
#endif
|
|
|
|
#if !(MESHTASTIC_EXCLUDE_PKI)
|
|
deviceMetadata.hasPKC = true;
|
|
#endif
|
|
return deviceMetadata;
|
|
}
|
|
|
|
#if !MESHTASTIC_EXCLUDE_I2C
|
|
void scannerToSensorsMap(const std::unique_ptr<ScanI2CTwoWire> &i2cScanner, ScanI2C::DeviceType deviceType,
|
|
meshtastic_TelemetrySensorType sensorType)
|
|
{
|
|
auto found = i2cScanner->find(deviceType);
|
|
if (found.type != ScanI2C::DeviceType::NONE) {
|
|
nodeTelemetrySensorsMap[sensorType].first = found.address.address;
|
|
nodeTelemetrySensorsMap[sensorType].second = i2cScanner->fetchI2CBus(found.address);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef PIO_UNIT_TESTING
|
|
void loop()
|
|
{
|
|
runASAP = false;
|
|
|
|
#ifdef ARCH_ESP32
|
|
esp32Loop();
|
|
#endif
|
|
#ifdef ARCH_NRF52
|
|
nrf52Loop();
|
|
#endif
|
|
powerCommandsCheck();
|
|
|
|
#ifdef DEBUG_STACK
|
|
static uint32_t lastPrint = 0;
|
|
if (!Throttle::isWithinTimespanMs(lastPrint, 10 * 1000L)) {
|
|
lastPrint = millis();
|
|
meshtastic::printThreadInfo("main");
|
|
}
|
|
#endif
|
|
|
|
service->loop();
|
|
|
|
long delayMsec = mainController.runOrDelay();
|
|
|
|
// We want to sleep as long as possible here - because it saves power
|
|
if (!runASAP && loopCanSleep()) {
|
|
mainDelay.delay(delayMsec);
|
|
}
|
|
}
|
|
|
|
#endif |