diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000000..e608f4ed0b0 --- /dev/null +++ b/.clang-format @@ -0,0 +1,190 @@ +# Source: https://github.com/arduino/tooling-project-assets/tree/main/other/clang-format-configuration +--- +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignConsecutiveMacros: None +AlignEscapedNewlines: DontAlign +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: AllIfsAndElse +AllowShortLambdasOnASingleLine: Empty +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: No +AttributeMacros: + - __capability +BasedOnStyle: LLVM +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAfterJavaFieldAnnotations: false +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Attach +BreakBeforeConceptDeclarations: false +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakConstructorInitializersBeforeComma: false +BreakInheritanceList: BeforeColon +BreakStringLiterals: false +ColumnLimit: 0 +CommentPragmas: '' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: false +DeriveLineEnding: true +DerivePointerAlignment: true +DisableFormat: false +EmptyLineAfterAccessModifier: Leave +EmptyLineBeforeAccessModifier: Leave +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: true +IndentCaseLabels: true +IndentExternBlock: Indent +IndentGotoLabels: false +IndentPPDirectives: None +IndentRequires: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +Language: Cpp +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 100000 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PPIndentWidth: -1 +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 1 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 1 +PenaltyBreakFirstLessLess: 1 +PenaltyBreakOpenParenthesis: 1 +PenaltyBreakString: 1 +PenaltyBreakTemplateDeclaration: 1 +PenaltyExcessCharacter: 1 +PenaltyIndentedWhitespace: 1 +PenaltyReturnTypeOnItsOwnLine: 1 +PointerAlignment: Right +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: false +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 0 +SortIncludes: Never +SortJavaStaticImport: Before +SortUsingDeclarations: false +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Leave +SpacesInCStyleCastParentheses: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +SpacesInLineCommentPrefix: + Minimum: 0 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 2 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME diff --git a/.codespellrc b/.codespellrc new file mode 100644 index 00000000000..690782793dd --- /dev/null +++ b/.codespellrc @@ -0,0 +1,9 @@ +[codespell] +# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/spell-check/.codespellrc +# In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here: +ignore-words-list = ba,licence,ot,dout,als,exten,acount,totaly,pasttime +skip = ./.git,./.licenses,__pycache__,.clang-format,.codespellrc,.editorconfig,.flake8,.prettierignore,.yamllint.yml,.gitignore,boards.txt,platform.txt,programmers.txt +builtin = clear,informal,en-GB_to_en-US +check-filenames = +check-hidden = +write-changes = diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..eda8544321b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,60 @@ +# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/general/.editorconfig +# See: https://editorconfig.org/ +# The formatting style defined in this file is the official standardized style to be used in all Arduino Tooling +# projects and should not be modified. +# Note: indent style for each file type is defined even when it matches the universal config in order to make it clear +# that this type has an official style. + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{adoc,asc,asciidoc}] +indent_size = 2 +indent_style = space + +[*.{bash,sh}] +indent_size = 2 +indent_style = space + +[*.{c,cc,cp,cpp,cxx,h,hh,hpp,hxx,ii,inl,ino,ixx,pde,tpl,tpp,txx}] +indent_size = 2 +indent_style = space + +[*.{go,mod}] +indent_style = tab + +[*.java] +indent_size = 2 +indent_style = space + +[*.{js,jsx,json,jsonc,json5,ts,tsx}] +indent_size = 2 +indent_style = space + +[*.{md,mdx,mkdn,mdown,markdown}] +indent_size = unset +indent_style = space + +[*.proto] +indent_size = 2 +indent_style = space + +[*.py] +indent_size = 4 +indent_style = space + +[*.svg] +indent_size = 2 +indent_style = space + +[*.{yaml,yml}] +indent_size = 2 +indent_style = space + +[{.gitconfig,.gitmodules}] +indent_style = tab diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000000..881c4c629c2 --- /dev/null +++ b/.flake8 @@ -0,0 +1,12 @@ +# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/check-python/.flake8 +# See: https://flake8.pycqa.org/en/latest/user/configuration.html +# The code style defined in this file is the official standardized style to be used in all Arduino tooling projects and +# should not be modified. + +[flake8] +doctests = True +# W503 and W504 are mutually exclusive. PEP 8 recommends line break before. +ignore = W503,E203 +max-complexity = 10 +max-line-length = 120 +select = E,W,F,C,N diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 00000000000..08ae9a0c67c --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,62 @@ +name: Pre-commit check + +on: + pull_request: + types: [opened, reopened, synchronize, labeled] + +jobs: + lint: + if: | + contains(github.event.pull_request.labels.*.name, 'Status: Pending Merge') + name: Checking if any fixes are needed + runs-on: ubuntu-latest + steps: + - name: Checkout latest commit + uses: actions/checkout@v4 + with: + fetch-depth: 2 + + - name: Set up Python 3 + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Get Python version hash + run: | + echo "Using $(python -VV)" + echo "PY_HASH=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV + + - name: Restore pre-commit cache + uses: actions/cache/restore@v4 + id: restore-cache + with: + path: | + ~/.cache/pre-commit + ~/.cache/pip + key: pre-commit|${{ env.PY_HASH }}|${{ hashFiles('.pre-commit-config.yaml', '.github/workflows/pre-commit.yml') }} + + - name: Install python dependencies + run: python -m pip install pre-commit docutils + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v42.0.2 + + - name: Run pre-commit hooks in changed files + run: pre-commit run --color=always --show-diff-on-failure --files ${{ steps.changed-files.outputs.all_changed_files }} + + - name: Save pre-commit cache + uses: actions/cache/save@v4 + if: ${{ always() && steps.restore-cache.outputs.cache-hit != 'true' }} + continue-on-error: true + with: + path: | + ~/.cache/pre-commit + ~/.cache/pip + key: ${{ steps.restore-cache.outputs.cache-primary-key }} + + - name: Push changes using pre-commit-ci-lite + uses: pre-commit-ci/lite-action@v1.0.2 + if: always() + with: + msg: "ci(pre-commit): Apply automatic fixes" diff --git a/.gitignore b/.gitignore index 2eea4128f55..67ae15c2bf9 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,7 @@ tools/openocd-esp32 # Ignore build folder /build - + # Ignore files built by Visual Studio/Visual Micro [Dd]ebug/ [Rr]elease/ @@ -44,3 +44,9 @@ debug.cfg debug.svd debug_custom.json libraries/Insights/examples/*/*.ino.zip + +# Vale Style +.vale/styles/* +!.vale/styles/Vocab/ +.vale/styles/Vocab/* +!.vale/styles/Vocab/Espressif/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000000..bc187482041 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,66 @@ +exclude: ".github/.*" + +default_language_version: + # force all unspecified python hooks to run python3 + python: python3 + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: "v4.5.0" + hooks: + - id: check-case-conflict + - id: check-symlinks + - id: debug-statements + - id: destroyed-symlinks + - id: detect-private-key + - id: end-of-file-fixer + exclude: ^.*\.(bin|BIN)$ + - id: mixed-line-ending + args: [--fix=lf] + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] + - repo: https://github.com/codespell-project/codespell + rev: "v2.2.4" + hooks: + - id: codespell + exclude: ^.*\.(svd|SVD)$ + stages: [manual] + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: "v15.0.7" + hooks: + - id: clang-format + types_or: [c, c++] + - repo: https://github.com/psf/black-pre-commit-mirror + rev: "22.10.0" + hooks: + - id: black + types_or: [python] + args: [--line-length=120] #From the arduino code style. Add as argument rather than creating a new config file. + - repo: https://github.com/PyCQA/flake8 + rev: "7.0.0" + hooks: + - id: flake8 + types_or: [python] + additional_dependencies: + - flake8-bugbear + - flake8-comprehensions + - flake8-simplify + - repo: https://github.com/pre-commit/mirrors-prettier + rev: "v3.1.0" + hooks: + - id: prettier + types_or: [yaml] + - repo: https://github.com/errata-ai/vale + rev: "v3.0.7" + hooks: + - id: vale + name: vale-sync + language_version: "1.21.6" + pass_filenames: false + args: [sync] + types_or: [markdown, rst] + stages: [manual] + - id: vale + language_version: "1.21.6" + types_or: [markdown, rst] + stages: [manual] diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000000..58b8966740f --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +__pycache__/ +.clang-format +.licenses/ +/.git/ diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 00000000000..d51d3016a57 --- /dev/null +++ b/.vale.ini @@ -0,0 +1,118 @@ +################### +### Vale Config ### +################### + +# This is a Vale linter configuration file. +# - Repo: arduino-esp32 +# - Based on Default config: v0-1-1 +# It lists all necessary parameters to configure Vale for your project. +# For official documentation on all config settings, see +# https://vale.sh/docs/topics/config + + +############## +### Global ### +############## + +# This section lists core settings applying to Vale itself. + + +# Specify path to external resources (e.g., styles and vocab files). +# The path value may be absolute or relative to this configuration file. +StylesPath = .vale/styles + + +# Specify the minimum alert severity that Vale will report. +MinAlertLevel = suggestion # "suggestion", "warning", or "error" + + +# Specify vocabulary for special treatment. +# Create a folder in /Vocab//and add its name here +# The folder should contain two files: +# - accept.txt -- lists words with accepted case-sensitive spelling +# - reject.txt -- lists words whose occurrences throw an error +# Vocab = Espressif + + +# Specify the packages to import into your project. +# A package is a zip file containing a number of rules (style) written in YAML. +# For a list of official packages, see Package Hub at https://vale.sh/hub/ +# For official documentation on packages, see +# https://vale.sh/docs/topics/packages/ +# Before linting, navigate to your project and run `vale sync` to download +# the official packages specified below. +# Packages = Package1, Package2, \ +# https://example.com/path/to/package/Package.zip +Packages = Google, Microsoft, RedHat, \ +https://dl.espressif.com/dl/esp-vale-config/Espressif-latest.zip + + +############### +### Formats ### +############### + +# This section enables association of "unknown" formats with the ones +# supported by Vale. For official documentation on supported formats, see +# https://vale.sh/docs/topics/scoping/ +[formats] + +# For example, treat MDX files as Markdown files. +# mdx = md + + +################################ +### Format-specific settings ### +################################ + +# This section lists the settings that apply to specific file formats +# based on their glob pattern. +# Settings provided under a more specific glob pattern, +# such as [*.{md,txt}] will override those in [*]. +[*.{md,rst}] + + +# Enable styles to activate all rules included in them. +# BasedOnStyles = Style1, Style2 +BasedOnStyles = Vale, Espressif-latest + + +### Deactivate individual rules ### +### in enabled styles. +# Style1.Rule1 = NO +Vale.Repetition = NO +Vale.Spelling = NO +Espressif-latest.Admonitions = NO +Espressif-latest.Contractions = NO +Espressif-latest.Monospace = NO + + +### Change default severity level ### +### of an activated rule. +# Choose between "suggestion", "warning", or "error". +# Style1.Rule2 = error + + +### Activate individual rules ### +### in non-enabled styles stored in . +# Style1.Rule = YES +Google.Gender = YES +Google.GenderBias = YES +Google.Slang = YES +Google.Spacing = YES +Microsoft.DateNumbers = YES +Microsoft.Ellipses = YES +Microsoft.FirstPerson = YES +Microsoft.Hyphens = YES +Microsoft.Ordinal = YES +Microsoft.OxfordComma = YES +Microsoft.Percentages = YES +Microsoft.RangeTime = YES +Microsoft.Semicolon = YES +Microsoft.SentenceLength = YES +Microsoft.Suspended = YES +Microsoft.Units = YES +Microsoft.URLFormat = YES +Microsoft.We = YES +Microsoft.Wordiness = YES +RedHat.Contractions = YES +RedHat.RepeatedWords = YES diff --git a/CMakeLists.txt b/CMakeLists.txt index cc294494f43..00552a77f74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,7 @@ set(ARDUINO_ALL_LIBRARIES LittleFS NetBIOS Network + PPP Preferences RainMaker SD_MMC @@ -157,6 +158,10 @@ set(ARDUINO_LIBRARY_LittleFS_SRCS libraries/LittleFS/src/LittleFS.cpp) set(ARDUINO_LIBRARY_NetBIOS_SRCS libraries/NetBIOS/src/NetBIOS.cpp) +set(ARDUINO_LIBRARY_PPP_SRCS + libraries/PPP/src/PPP.cpp + libraries/PPP/src/ppp.c) + set(ARDUINO_LIBRARY_Preferences_SRCS libraries/Preferences/src/Preferences.cpp) set(ARDUINO_LIBRARY_RainMaker_SRCS diff --git a/Kconfig.projbuild b/Kconfig.projbuild index af772bd4618..3e45e358d55 100644 --- a/Kconfig.projbuild +++ b/Kconfig.projbuild @@ -321,6 +321,16 @@ config ARDUINO_SELECTIVE_Networking depends on ARDUINO_SELECTIVE_COMPILATION default y +config ARDUINO_SELECTIVE_Ethernet + bool "Enable Ethernet" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + +config ARDUINO_SELECTIVE_PPP + bool "Enable PPP" + depends on ARDUINO_SELECTIVE_COMPILATION + default y + config ARDUINO_SELECTIVE_ArduinoOTA bool "Enable ArduinoOTA" depends on ARDUINO_SELECTIVE_COMPILATION && ARDUINO_SELECTIVE_Networking diff --git a/cores/esp32/esp32-hal-periman.c b/cores/esp32/esp32-hal-periman.c index dd3a2f32a21..8b5fa431090 100644 --- a/cores/esp32/esp32-hal-periman.c +++ b/cores/esp32/esp32-hal-periman.c @@ -54,14 +54,17 @@ const char* perimanGetTypeName(peripheral_bus_type_t type) { case ESP32_BUS_TYPE_I2S_STD_WS: return "I2S_STD_WS"; case ESP32_BUS_TYPE_I2S_STD_DOUT: return "I2S_STD_DOUT"; case ESP32_BUS_TYPE_I2S_STD_DIN: return "I2S_STD_DIN"; + case ESP32_BUS_TYPE_I2S_TDM_MCLK: return "I2S_TDM_MCLK"; case ESP32_BUS_TYPE_I2S_TDM_BCLK: return "I2S_TDM_BCLK"; case ESP32_BUS_TYPE_I2S_TDM_WS: return "I2S_TDM_WS"; case ESP32_BUS_TYPE_I2S_TDM_DOUT: return "I2S_TDM_DOUT"; case ESP32_BUS_TYPE_I2S_TDM_DIN: return "I2S_TDM_DIN"; + case ESP32_BUS_TYPE_I2S_PDM_TX_CLK: return "I2S_PDM_TX_CLK"; case ESP32_BUS_TYPE_I2S_PDM_TX_DOUT0: return "I2S_PDM_TX_DOUT0"; case ESP32_BUS_TYPE_I2S_PDM_TX_DOUT1: return "I2S_PDM_TX_DOUT1"; + case ESP32_BUS_TYPE_I2S_PDM_RX_CLK: return "I2S_PDM_RX_CLK"; case ESP32_BUS_TYPE_I2S_PDM_RX_DIN0: return "I2S_PDM_RX_DIN0"; case ESP32_BUS_TYPE_I2S_PDM_RX_DIN1: return "I2S_PDM_RX_DIN1"; @@ -104,6 +107,12 @@ const char* perimanGetTypeName(peripheral_bus_type_t type) { case ESP32_BUS_TYPE_ETHERNET_MCD: return "ETHERNET_MCD"; case ESP32_BUS_TYPE_ETHERNET_MDIO: return "ETHERNET_MDIO"; case ESP32_BUS_TYPE_ETHERNET_PWR: return "ETHERNET_PWR"; +#endif +#if CONFIG_LWIP_PPP_SUPPORT + case ESP32_BUS_TYPE_PPP_TX: return "PPP_MODEM_TX"; + case ESP32_BUS_TYPE_PPP_RX: return "PPP_MODEM_RX"; + case ESP32_BUS_TYPE_PPP_RTS: return "PPP_MODEM_RTS"; + case ESP32_BUS_TYPE_PPP_CTS: return "PPP_MODEM_CTS"; #endif default: return "UNKNOWN"; } diff --git a/cores/esp32/esp32-hal-periman.h b/cores/esp32/esp32-hal-periman.h index aa3de699502..1989ecdb35a 100644 --- a/cores/esp32/esp32-hal-periman.h +++ b/cores/esp32/esp32-hal-periman.h @@ -103,6 +103,12 @@ typedef enum { ESP32_BUS_TYPE_ETHERNET_MCD, // IO is used as ETHERNET MCD pin ESP32_BUS_TYPE_ETHERNET_MDIO, // IO is used as ETHERNET MDIO pin ESP32_BUS_TYPE_ETHERNET_PWR, // IO is used as ETHERNET PWR pin +#endif +#if CONFIG_LWIP_PPP_SUPPORT + ESP32_BUS_TYPE_PPP_TX, // IO is used as PPP Modem TX pin + ESP32_BUS_TYPE_PPP_RX, // IO is used as PPP Modem RX pin + ESP32_BUS_TYPE_PPP_RTS, // IO is used as PPP Modem RTS pin + ESP32_BUS_TYPE_PPP_CTS, // IO is used as PPP Modem CTS pin #endif ESP32_BUS_TYPE_MAX } peripheral_bus_type_t; diff --git a/idf_component.yml b/idf_component.yml index 634d364ba3a..9e7b566ee3b 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -45,6 +45,7 @@ dependencies: idf: ">=5.1" # mdns 1.2.1 is necessary to build H2 with no WiFi mdns: "^1.2.3" + espressif/esp_modem: "^1.1.0" chmorgan/esp-libhelix-mp3: version: "1.0.3" require: public diff --git a/libraries/Network/src/NetworkEvents.cpp b/libraries/Network/src/NetworkEvents.cpp index 5f24e23a894..5db470f4fce 100644 --- a/libraries/Network/src/NetworkEvents.cpp +++ b/libraries/Network/src/NetworkEvents.cpp @@ -334,13 +334,13 @@ const char * NetworkEvents::eventName(arduino_event_id_t id) { case ARDUINO_EVENT_ETH_LOST_IP: return "ETH_LOST_IP"; case ARDUINO_EVENT_ETH_GOT_IP6: return "ETH_GOT_IP6"; - // case ARDUINO_EVENT_PPP_START: return "PPP_START"; - // case ARDUINO_EVENT_PPP_STOP: return "PPP_STOP"; - // case ARDUINO_EVENT_PPP_CONNECTED: return "PPP_CONNECTED"; - // case ARDUINO_EVENT_PPP_DISCONNECTED: return "PPP_DISCONNECTED"; - // case ARDUINO_EVENT_PPP_GOT_IP: return "PPP_GOT_IP"; - // case ARDUINO_EVENT_PPP_LOST_IP: return "PPP_LOST_IP"; - // case ARDUINO_EVENT_PPP_GOT_IP6: return "PPP_GOT_IP6"; + case ARDUINO_EVENT_PPP_START: return "PPP_START"; + case ARDUINO_EVENT_PPP_STOP: return "PPP_STOP"; + case ARDUINO_EVENT_PPP_CONNECTED: return "PPP_CONNECTED"; + case ARDUINO_EVENT_PPP_DISCONNECTED: return "PPP_DISCONNECTED"; + case ARDUINO_EVENT_PPP_GOT_IP: return "PPP_GOT_IP"; + case ARDUINO_EVENT_PPP_LOST_IP: return "PPP_LOST_IP"; + case ARDUINO_EVENT_PPP_GOT_IP6: return "PPP_GOT_IP6"; #if SOC_WIFI_SUPPORTED case ARDUINO_EVENT_WIFI_OFF: return "WIFI_OFF"; case ARDUINO_EVENT_WIFI_READY: return "WIFI_READY"; diff --git a/libraries/Network/src/NetworkEvents.h b/libraries/Network/src/NetworkEvents.h index eaee117d0fc..5ee4972fdd9 100644 --- a/libraries/Network/src/NetworkEvents.h +++ b/libraries/Network/src/NetworkEvents.h @@ -78,13 +78,13 @@ typedef enum { ARDUINO_EVENT_PROV_CRED_FAIL, ARDUINO_EVENT_PROV_CRED_SUCCESS, #endif - // ARDUINO_EVENT_PPP_START, - // ARDUINO_EVENT_PPP_STOP, - // ARDUINO_EVENT_PPP_CONNECTED, - // ARDUINO_EVENT_PPP_DISCONNECTED, - // ARDUINO_EVENT_PPP_GOT_IP, - // ARDUINO_EVENT_PPP_LOST_IP, - // ARDUINO_EVENT_PPP_GOT_IP6, + ARDUINO_EVENT_PPP_START, + ARDUINO_EVENT_PPP_STOP, + ARDUINO_EVENT_PPP_CONNECTED, + ARDUINO_EVENT_PPP_DISCONNECTED, + ARDUINO_EVENT_PPP_GOT_IP, + ARDUINO_EVENT_PPP_LOST_IP, + ARDUINO_EVENT_PPP_GOT_IP6, ARDUINO_EVENT_MAX } arduino_event_id_t; @@ -146,6 +146,7 @@ class NetworkEvents { friend class ESP_NetworkInterface; friend class ETHClass; + friend class PPPClass; #if SOC_WIFI_SUPPORTED friend class STAClass; friend class APClass; diff --git a/libraries/Network/src/NetworkInterface.cpp b/libraries/Network/src/NetworkInterface.cpp index 99896d9060c..e84ab534114 100644 --- a/libraries/Network/src/NetworkInterface.cpp +++ b/libraries/Network/src/NetworkInterface.cpp @@ -71,9 +71,9 @@ void NetworkInterface::_onIpEvent(int32_t event_id, void* event_data){ arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_GOT_IP; } else #endif - // if(_interface_id == ESP_NETIF_ID_PPP){ - // arduino_event.event_id = ARDUINO_EVENT_PPP_GOT_IP; - // } else + if(_interface_id == ESP_NETIF_ID_PPP){ + arduino_event.event_id = ARDUINO_EVENT_PPP_GOT_IP; + } else if(_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX){ arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP; } @@ -87,9 +87,9 @@ void NetworkInterface::_onIpEvent(int32_t event_id, void* event_data){ arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_LOST_IP; } else #endif - // if(_interface_id == ESP_NETIF_ID_PPP){ - // arduino_event.event_id = ARDUINO_EVENT_PPP_LOST_IP; - // } else + if(_interface_id == ESP_NETIF_ID_PPP){ + arduino_event.event_id = ARDUINO_EVENT_PPP_LOST_IP; + } else if(_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX){ arduino_event.event_id = ARDUINO_EVENT_ETH_LOST_IP; } @@ -115,9 +115,9 @@ void NetworkInterface::_onIpEvent(int32_t event_id, void* event_data){ arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_GOT_IP6; } else #endif - // if(_interface_id == ESP_NETIF_ID_PPP){ - // arduino_event.event_id = ARDUINO_EVENT_PPP_GOT_IP6; - // } else + if(_interface_id == ESP_NETIF_ID_PPP){ + arduino_event.event_id = ARDUINO_EVENT_PPP_GOT_IP6; + } else if(_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX){ arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP6; } @@ -549,7 +549,7 @@ String NetworkInterface::impl_name(void) const char netif_name[8]; esp_err_t err = esp_netif_get_netif_impl_name(_esp_netif, netif_name); if(err != ESP_OK){ - log_e("Failed to get netif impl_name: %d", err); + log_e("Failed to get netif impl_name: 0x%04x %s", err, esp_err_to_name(err)); return String(""); } return String(netif_name); @@ -578,7 +578,7 @@ bool NetworkInterface::setDefault() } esp_err_t err = esp_netif_set_default_netif(_esp_netif); if(err != ESP_OK){ - log_e("Failed to set default netif: %d", err); + log_e("Failed to set default netif: 0x%04x %s", err, esp_err_to_name(err)); return false; } return true; @@ -594,15 +594,15 @@ bool NetworkInterface::isDefault() const uint8_t * NetworkInterface::macAddress(uint8_t* mac) const { - if(!mac || _esp_netif == NULL){ + if(!mac || _esp_netif == NULL || _interface_id == ESP_NETIF_ID_PPP){ return NULL; } + esp_err_t err = esp_netif_get_mac(_esp_netif, mac); if(err != ESP_OK){ - log_e("Failed to get netif mac: %d", err); + log_e("Failed to get netif mac: 0x%04x %s", err, esp_err_to_name(err)); return NULL; } - // getMac(mac); return mac; } diff --git a/libraries/PPP/examples/PPP_Basic/PPP_Basic.ino b/libraries/PPP/examples/PPP_Basic/PPP_Basic.ino new file mode 100644 index 00000000000..78fda9d18bf --- /dev/null +++ b/libraries/PPP/examples/PPP_Basic/PPP_Basic.ino @@ -0,0 +1,131 @@ +#include + +#define PPP_MODEM_APN "internet" +#define PPP_MODEM_PIN "0000" // or NULL + +// WaveShare SIM7600 HW Flow Control +#define PPP_MODEM_RST 25 +#define PPP_MODEM_RST_LOW false //active HIGH +#define PPP_MODEM_TX 21 +#define PPP_MODEM_RX 22 +#define PPP_MODEM_RTS 26 +#define PPP_MODEM_CTS 27 +#define PPP_MODEM_FC ESP_MODEM_FLOW_CONTROL_HW +#define PPP_MODEM_MODEL PPP_MODEM_SIM7600 + +// SIM800 basic module with just TX,RX and RST +// #define PPP_MODEM_RST 0 +// #define PPP_MODEM_RST_LOW true //active LOW +// #define PPP_MODEM_TX 2 +// #define PPP_MODEM_RX 19 +// #define PPP_MODEM_RTS -1 +// #define PPP_MODEM_CTS -1 +// #define PPP_MODEM_FC ESP_MODEM_FLOW_CONTROL_NONE +// #define PPP_MODEM_MODEL PPP_MODEM_SIM800 + +void onEvent(arduino_event_id_t event, arduino_event_info_t info) +{ + switch (event) { + case ARDUINO_EVENT_PPP_START: + Serial.println("PPP Started"); + break; + case ARDUINO_EVENT_PPP_CONNECTED: + Serial.println("PPP Connected"); + break; + case ARDUINO_EVENT_PPP_GOT_IP: + Serial.println("PPP Got IP"); + break; + case ARDUINO_EVENT_PPP_LOST_IP: + Serial.println("PPP Lost IP"); + break; + case ARDUINO_EVENT_PPP_DISCONNECTED: + Serial.println("PPP Disconnected"); + break; + case ARDUINO_EVENT_PPP_STOP: + Serial.println("PPP Stopped"); + break; + default: + break; + } +} + +void testClient(const char * host, uint16_t port) { + NetworkClient client; + if (!client.connect(host, port)) { + Serial.println("Connection Failed"); + return; + } + client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host); + while (client.connected() && !client.available()); + while (client.available()) { + client.read();//Serial.write(client.read()); + } + + Serial.println("Connection Success"); + client.stop(); +} + +void setup() { + Serial.begin(115200); + + // Listen for modem events + Network.onEvent(onEvent); + + // Configure the modem + PPP.setApn(PPP_MODEM_APN); + PPP.setPin(PPP_MODEM_PIN); + PPP.setResetPin(PPP_MODEM_RST, PPP_MODEM_RST_LOW); + PPP.setPins(PPP_MODEM_TX, PPP_MODEM_RX, PPP_MODEM_RTS, PPP_MODEM_CTS, PPP_MODEM_FC); + + Serial.println("Starting the modem. It might take a while!"); + PPP.begin(PPP_MODEM_MODEL); + + Serial.print("Manufacturer: "); Serial.println(PPP.cmd("AT+CGMI", 10000)); + Serial.print("Model: "); Serial.println(PPP.moduleName()); + Serial.print("IMEI: "); Serial.println(PPP.IMEI()); + + bool attached = PPP.attached(); + if(!attached){ + int i=0; + unsigned int s = millis(); + Serial.print("Waiting to connect to network"); + while(!attached && ((++i) < 600)){ + Serial.print("."); + delay(100); + attached = PPP.attached(); + } + Serial.print((millis() - s) / 1000.0, 1); + Serial.println("s"); + attached = PPP.attached(); + } + + Serial.print("Attached: "); Serial.println(attached); + Serial.print("State: "); Serial.println(PPP.radioState()); + if(attached){ + Serial.print("Operator: "); Serial.println(PPP.operatorName()); + Serial.print("IMSI: "); Serial.println(PPP.IMSI()); + Serial.print("RSSI: "); Serial.println(PPP.RSSI()); + int ber = PPP.BER(); + if(ber > 0){ + Serial.print("BER: "); Serial.println(ber); + Serial.print("NetMode: "); Serial.println(PPP.networkMode()); + } + + Serial.println("Switching to data mode..."); + PPP.mode(ESP_MODEM_MODE_CMUX); // Data and Command mixed mode + if(!PPP.waitStatusBits(ESP_NETIF_CONNECTED_BIT, 1000)){ + Serial.println("Failed to connect to internet!"); + } else { + Serial.println("Connected to internet!"); + } + } else { + Serial.println("Failed to connect to network!"); + } +} + +void loop() { + if (PPP.connected()) { + testClient("google.com", 80); + } + delay(20000); +} diff --git a/libraries/PPP/library.properties b/libraries/PPP/library.properties new file mode 100644 index 00000000000..abc4fb21a71 --- /dev/null +++ b/libraries/PPP/library.properties @@ -0,0 +1,9 @@ +name=PPP +version=1.0.0 +author=Hristo Gochkov +maintainer=Hristo Gochkov +sentence=Enables network connection using GSM Modem. +paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through GSM Modem. +category=Communication +url= +architectures=esp32 diff --git a/libraries/PPP/src/PPP.cpp b/libraries/PPP/src/PPP.cpp new file mode 100644 index 00000000000..6227fcf7f12 --- /dev/null +++ b/libraries/PPP/src/PPP.cpp @@ -0,0 +1,817 @@ +#define ARDUINO_CORE_BUILD +#include "PPP.h" +#if CONFIG_LWIP_PPP_SUPPORT +#include "esp32-hal-periman.h" +#include "esp_netif.h" +#include "esp_netif_ppp.h" +#include +#include "driver/uart.h" +#include "hal/uart_ll.h" + +typedef struct { void * arg; } PdpContext; +#include "esp_modem_api.h" + +// Because of how esp_modem functions are declared, we need to workaround some APIs that take strings as input (output works OK) +// Following APIs work only when called through this interface +extern "C" { + esp_err_t _esp_modem_at(esp_modem_dce_t *dce_wrap, const char *at, char *p_out, int timeout); + esp_err_t _esp_modem_at_raw(esp_modem_dce_t *dce_wrap, const char *cmd, char *p_out, const char *pass, const char *fail, int timeout); + esp_err_t _esp_modem_send_sms(esp_modem_dce_t *dce_wrap, const char *number, const char *message); + esp_err_t _esp_modem_set_pin(esp_modem_dce_t *dce_wrap, const char *pin); + esp_err_t _esp_modem_set_operator(esp_modem_dce_t *dce_wrap, int mode, int format, const char *oper); + esp_err_t _esp_modem_set_network_bands(esp_modem_dce_t *dce_wrap, const char *mode, const int *bands, int size); +}; + +static PPPClass * _esp_modem = NULL; +static esp_event_handler_instance_t _ppp_ev_instance = NULL; + +#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE +static const char * _ppp_event_name(int32_t event_id){ + switch(event_id){ + case NETIF_PPP_ERRORNONE : return "No error."; + case NETIF_PPP_ERRORPARAM : return "Invalid parameter."; + case NETIF_PPP_ERROROPEN : return "Unable to open PPP session."; + case NETIF_PPP_ERRORDEVICE : return "Invalid I/O device for PPP."; + case NETIF_PPP_ERRORALLOC : return "Unable to allocate resources."; + case NETIF_PPP_ERRORUSER : return "User interrupt."; + case NETIF_PPP_ERRORCONNECT : return "Connection lost."; + case NETIF_PPP_ERRORAUTHFAIL : return "Failed authentication challenge."; + case NETIF_PPP_ERRORPROTOCOL : return "Failed to meet protocol."; + case NETIF_PPP_ERRORPEERDEAD : return "Connection timeout"; + case NETIF_PPP_ERRORIDLETIMEOUT : return "Idle Timeout"; + case NETIF_PPP_ERRORCONNECTTIME : return "Max connect time reached"; + case NETIF_PPP_ERRORLOOPBACK : return "Loopback detected"; + case NETIF_PPP_PHASE_DEAD : return "Phase Dead"; + case NETIF_PPP_PHASE_MASTER : return "Phase Master"; + case NETIF_PPP_PHASE_HOLDOFF : return "Phase Hold Off"; + case NETIF_PPP_PHASE_INITIALIZE : return "Phase Initialize"; + case NETIF_PPP_PHASE_SERIALCONN : return "Phase Serial Conn"; + case NETIF_PPP_PHASE_DORMANT : return "Phase Dormant"; + case NETIF_PPP_PHASE_ESTABLISH : return "Phase Establish"; + case NETIF_PPP_PHASE_AUTHENTICATE: return "Phase Authenticate"; + case NETIF_PPP_PHASE_CALLBACK : return "Phase Callback"; + case NETIF_PPP_PHASE_NETWORK : return "Phase Network"; + case NETIF_PPP_PHASE_RUNNING : return "Phase Running"; + case NETIF_PPP_PHASE_TERMINATE : return "Phase Terminate"; + case NETIF_PPP_PHASE_DISCONNECT : return "Phase Disconnect"; + case NETIF_PPP_CONNECT_FAILED : return "Connect Failed"; + default: break; + } + return "UNKNOWN"; +} + +static const char * _ppp_terminal_error_name(esp_modem_terminal_error_t err){ + switch(err){ + case ESP_MODEM_TERMINAL_BUFFER_OVERFLOW: return "Buffer Overflow"; + case ESP_MODEM_TERMINAL_CHECKSUM_ERROR: return "Checksum Error"; + case ESP_MODEM_TERMINAL_UNEXPECTED_CONTROL_FLOW: return "Unexpected Control Flow"; + case ESP_MODEM_TERMINAL_DEVICE_GONE: return "Device Gone"; + case ESP_MODEM_TERMINAL_UNKNOWN_ERROR: return "Unknown Error"; + default: break; + } + return "UNKNOWN"; +} +#endif + +static void _ppp_event_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { + if (event_base == NETIF_PPP_STATUS){ + if(_esp_modem != NULL){ + _esp_modem->_onPppEvent(event_id, event_data); + } + } +} + +static void onPppArduinoEvent(arduino_event_id_t event, arduino_event_info_t info) +{ + if(event >= ARDUINO_EVENT_PPP_START && event <= ARDUINO_EVENT_PPP_GOT_IP6){ + _esp_modem->_onPppArduinoEvent(event, info); + } +} + +// PPP Error Callback +static void _ppp_error_cb(esp_modem_terminal_error_t err){ + log_v("PPP Driver Error %ld: %s", err, _ppp_terminal_error_name(err)); +} + +// PPP Arduino Events Callback +void PPPClass::_onPppArduinoEvent(arduino_event_id_t event, arduino_event_info_t info){ + log_v("PPP Arduino Event %ld: %s", event, Network.eventName(event)); + // if(event == ARDUINO_EVENT_PPP_GOT_IP){ + // if((getStatusBits() & ESP_NETIF_CONNECTED_BIT) == 0){ + // setStatusBits(ESP_NETIF_CONNECTED_BIT); + // arduino_event_t arduino_event; + // arduino_event.event_id = ARDUINO_EVENT_PPP_CONNECTED; + // Network.postEvent(&arduino_event); + // } + // } else + if(event == ARDUINO_EVENT_PPP_LOST_IP){ + if((getStatusBits() & ESP_NETIF_CONNECTED_BIT) != 0){ + clearStatusBits(ESP_NETIF_CONNECTED_BIT); + arduino_event_t arduino_event; + arduino_event.event_id = ARDUINO_EVENT_PPP_DISCONNECTED; + Network.postEvent(&arduino_event); + } + } +} + +// PPP Driver Events Callback +void PPPClass::_onPppEvent(int32_t event, void* event_data){ + arduino_event_t arduino_event; + arduino_event.event_id = ARDUINO_EVENT_MAX; + + log_v("PPP Driver Event %ld: %s", event, _ppp_event_name(event)); + + if(event == NETIF_PPP_ERRORNONE){ + if((getStatusBits() & ESP_NETIF_CONNECTED_BIT) == 0){ + setStatusBits(ESP_NETIF_CONNECTED_BIT); + arduino_event_t arduino_event; + arduino_event.event_id = ARDUINO_EVENT_PPP_CONNECTED; + Network.postEvent(&arduino_event); + } + } + + if(arduino_event.event_id < ARDUINO_EVENT_MAX){ + Network.postEvent(&arduino_event); + } +} + +esp_modem_dce_t * PPPClass::handle() const { + return _dce; +} + +PPPClass::PPPClass() + :_dce(NULL) + ,_pin_tx(-1) + ,_pin_rx(-1) + ,_pin_rts(-1) + ,_pin_cts(-1) + ,_flow_ctrl(ESP_MODEM_FLOW_CONTROL_NONE) + ,_pin_rst(-1) + ,_pin_rst_act_low(true) + ,_pin(NULL) + ,_apn(NULL) + ,_rx_buffer_size(4096) + ,_tx_buffer_size(512) + ,_mode(ESP_MODEM_MODE_COMMAND) + ,_uart_num(UART_NUM_1) +{ +} + +PPPClass::~PPPClass() +{} + +bool PPPClass::pppDetachBus(void * bus_pointer){ + PPPClass *bus = (PPPClass *) bus_pointer; + bus->end(); + return true; +} + +void PPPClass::setResetPin(int8_t rst, bool active_low){ + _pin_rst = digitalPinToGPIONumber(rst); + _pin_rst_act_low = active_low; +} + +bool PPPClass::setPins(int8_t tx, int8_t rx, int8_t rts, int8_t cts, esp_modem_flow_ctrl_t flow_ctrl){ + perimanSetBusDeinit(ESP32_BUS_TYPE_PPP_TX, PPPClass::pppDetachBus); + perimanSetBusDeinit(ESP32_BUS_TYPE_PPP_RX, PPPClass::pppDetachBus); + perimanSetBusDeinit(ESP32_BUS_TYPE_PPP_RTS, PPPClass::pppDetachBus); + perimanSetBusDeinit(ESP32_BUS_TYPE_PPP_CTS, PPPClass::pppDetachBus); + + if(_pin_tx >= 0){ + if(!perimanClearPinBus(_pin_tx)){ return false; } + } + if(_pin_rx >= 0){ + if(!perimanClearPinBus(_pin_rx)){ return false; } + } + if(_pin_rts >= 0){ + if(!perimanClearPinBus(_pin_rts)){ return false; } + } + if(_pin_cts >= 0){ + if(!perimanClearPinBus(_pin_cts)){ return false; } + } + + _flow_ctrl = flow_ctrl; + _pin_tx = digitalPinToGPIONumber(tx); + _pin_rx = digitalPinToGPIONumber(rx); + _pin_rts = digitalPinToGPIONumber(rts); + _pin_cts = digitalPinToGPIONumber(cts); + + if(_pin_tx >= 0){ + if(!perimanSetPinBus(_pin_tx, ESP32_BUS_TYPE_PPP_TX, (void *)(this), -1, -1)){ return false; } + } + if(_pin_rx >= 0){ + if(!perimanSetPinBus(_pin_rx, ESP32_BUS_TYPE_PPP_RX, (void *)(this), -1, -1)){ return false; } + } + if(_pin_rts >= 0){ + if(!perimanSetPinBus(_pin_rts, ESP32_BUS_TYPE_PPP_RTS, (void *)(this), -1, -1)){ return false; } + } + if(_pin_cts >= 0){ + if(!perimanSetPinBus(_pin_cts, ESP32_BUS_TYPE_PPP_CTS, (void *)(this), -1, -1)){ return false; } + } + return true; +} + +bool PPPClass::begin(ppp_modem_model_t model, uint8_t uart_num, int baud_rate){ + esp_err_t ret = ESP_OK; + bool pin_ok = false; + int trys = 0; + + if(_esp_netif != NULL || _dce != NULL){ + log_w("PPP Already Started"); + return true; + } + + if(_apn == NULL){ + log_e("APN is not set. Call 'PPP.setApn()' first"); + return false; + } + + if(_pin_tx < 0 || _pin_rx < 0){ + log_e("UART pins not set. Call 'PPP.setPins()' first"); + return false; + } + + if((_pin_rts < 0 || _pin_cts < 0) && (_flow_ctrl != ESP_MODEM_FLOW_CONTROL_NONE)){ + log_e("UART CTS/RTS pins not set, but flow control is enabled!"); + return false; + } + + _uart_num = uart_num; + _esp_modem = this; + + Network.begin(); + + /* Listen for PPP status events */ + if(_ppp_ev_instance == NULL && esp_event_handler_instance_register(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &_ppp_event_cb, NULL, &_ppp_ev_instance)){ + log_e("event_handler_instance_register for NETIF_PPP_STATUS Failed!"); + return false; + } + + /* Configure the PPP netif */ + esp_netif_config_t cfg = ESP_NETIF_DEFAULT_PPP(); + _esp_netif = esp_netif_new(&cfg); + if(_esp_netif == NULL){ + log_e("esp_netif_new failed"); + return false; + } + + /* Attach to receive IP events */ + initNetif(ESP_NETIF_ID_PPP); + + /* Configure the DTE */ + esp_modem_dte_config_t dte_config = ESP_MODEM_DTE_DEFAULT_CONFIG(); + dte_config.uart_config.tx_io_num = _pin_tx; + dte_config.uart_config.rx_io_num = _pin_rx; + dte_config.uart_config.rts_io_num = _pin_rts; + dte_config.uart_config.cts_io_num = _pin_cts; + dte_config.uart_config.flow_control = _flow_ctrl; + dte_config.uart_config.rx_buffer_size = _rx_buffer_size; + dte_config.uart_config.tx_buffer_size = _tx_buffer_size; + dte_config.uart_config.port_num = _uart_num; + dte_config.uart_config.baud_rate = baud_rate; + + /* Configure the DCE */ + esp_modem_dce_config_t dce_config = ESP_MODEM_DCE_DEFAULT_CONFIG(_apn); + + /* Reset the Modem */ + if(_pin_rst >= 0){ + log_v("Resetting the modem"); + if(_pin_rst_act_low){ + pinMode(_pin_rst, OUTPUT_OPEN_DRAIN); + } else { + pinMode(_pin_rst, OUTPUT); + } + digitalWrite(_pin_rst, !_pin_rst_act_low); + delay(200); + digitalWrite(_pin_rst, _pin_rst_act_low); + delay(100); + } + + /* Start the DCE */ + _dce = esp_modem_new_dev((esp_modem_dce_device_t)model, &dte_config, &dce_config, _esp_netif); + if(_dce == NULL){ + log_e("esp_modem_new_dev failed"); + goto err; + } + + esp_modem_set_error_cb(_dce, _ppp_error_cb); + + /* Wait for Modem to respond */ + if(_pin_rst >= 0){ + // wait to be able to talk to the modem + log_v("Waiting for response from the modem"); + while(esp_modem_sync(_dce) != ESP_OK && trys < 100){ + trys++; + delay(500); + } + if(trys >= 100){ + log_e("Failed to wait for communication"); + goto err; + } + } else { + // try to communicate with the modem + if(esp_modem_sync(_dce) != ESP_OK){ + log_v("Modem does not respond to AT, maybe in DATA mode? ...exiting network mode"); + esp_modem_set_mode(_dce, ESP_MODEM_MODE_COMMAND); + if(esp_modem_sync(_dce) != ESP_OK){ + log_e("Modem failed to respond to AT!"); + goto err; + } + } + } + + /* enable flow control */ + if (dte_config.uart_config.flow_control == ESP_MODEM_FLOW_CONTROL_HW) { + ret = esp_modem_set_flow_control(_dce, 2, 2); //2/2 means HW Flow Control. + if (ret != ESP_OK) { + log_e("Failed to set the hardware flow control: [%d] %s", ret, esp_err_to_name(ret)); + goto err; + } + } + + /* check if PIN needed */ + if (esp_modem_read_pin(_dce, pin_ok) == ESP_OK && pin_ok == false) { + if (_pin == NULL || _esp_modem_set_pin(_dce, _pin) != ESP_OK) { + log_e("PIN verification failed!"); + goto err; + } + } + + Network.onSysEvent(onPppArduinoEvent); + + setStatusBits(ESP_NETIF_STARTED_BIT); + arduino_event_t arduino_event; + arduino_event.event_id = ARDUINO_EVENT_PPP_START; + Network.postEvent(&arduino_event); + + return true; + +err: + PPPClass::pppDetachBus((void *)(this)); + return false; +} + +void PPPClass::end(void) +{ + if(_esp_modem && _esp_netif && _dce){ + + if((getStatusBits() & ESP_NETIF_CONNECTED_BIT) != 0){ + clearStatusBits(ESP_NETIF_CONNECTED_BIT | ESP_NETIF_HAS_IP_BIT | ESP_NETIF_HAS_LOCAL_IP6_BIT | ESP_NETIF_HAS_GLOBAL_IP6_BIT); + arduino_event_t disconnect_event; + disconnect_event.event_id = ARDUINO_EVENT_PPP_DISCONNECTED; + Network.postEvent(&disconnect_event); + } + + clearStatusBits(ESP_NETIF_STARTED_BIT | ESP_NETIF_CONNECTED_BIT | ESP_NETIF_HAS_IP_BIT | ESP_NETIF_HAS_LOCAL_IP6_BIT | ESP_NETIF_HAS_GLOBAL_IP6_BIT | ESP_NETIF_HAS_STATIC_IP_BIT); + arduino_event_t arduino_event; + arduino_event.event_id = ARDUINO_EVENT_PPP_STOP; + Network.postEvent(&arduino_event); + } + + destroyNetif(); + + if(_ppp_ev_instance != NULL){ + if(esp_event_handler_unregister(NETIF_PPP_STATUS, ESP_EVENT_ANY_ID, &_ppp_event_cb) == ESP_OK){ + _ppp_ev_instance = NULL; + } + } + _esp_modem = NULL; + + Network.removeEvent(onPppArduinoEvent); + + if(_dce != NULL){ + esp_modem_destroy(_dce); + _dce = NULL; + } + + int8_t pin = -1; + if(_pin_tx != -1){ + pin = _pin_tx; + _pin_tx = -1; + perimanClearPinBus(pin); + } + if(_pin_rx != -1){ + pin = _pin_rx; + _pin_rx = -1; + perimanClearPinBus(pin); + } + if(_pin_rts != -1){ + pin = _pin_rts; + _pin_rts = -1; + perimanClearPinBus(pin); + } + if(_pin_cts != -1){ + pin = _pin_cts; + _pin_cts = -1; + perimanClearPinBus(pin); + } + + _mode = ESP_MODEM_MODE_COMMAND; +} + +bool PPPClass::sync() const +{ + if(_dce == NULL){ + return false; + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return false; + } + return esp_modem_sync(_dce) == ESP_OK; +} + +bool PPPClass::attached() const +{ + if(_dce == NULL){ + return false; + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return false; + } + + int m = 0; + esp_err_t err = esp_modem_get_network_attachment_state(_dce, m); + if (err != ESP_OK) { + // log_e("esp_modem_get_network_attachment_state failed with %d %s", err, esp_err_to_name(err)); + return false; + } + return m != 0; +} + +bool PPPClass::mode(esp_modem_dce_mode_t m){ + if(_dce == NULL){ + return 0; + } + + if(_mode == m){ + return true; + } + esp_err_t err = esp_modem_set_mode(_dce, m); + if (err != ESP_OK) { + log_e("esp_modem_set_mode failed with %d %s", err, esp_err_to_name(err)); + return false; + } + _mode = m; + return true; +} + +bool PPPClass::setApn(const char * apn){ + if(_apn != NULL){ + free((void *)_apn); + _apn = NULL; + } + if(apn != NULL){ + _apn = strdup(apn); + if(_apn == NULL){ + log_e("Failed to strdup APN"); + return false; + } + } + return true; +} + +bool PPPClass::setPin(const char * pin){ + if(_pin != NULL){ + free((void *)_pin); + _pin = NULL; + } + if(pin != NULL){ + for(int i=0; i 0x39){ + log_e("Bad character '%c' in PIN. Should be only digits", pin[i]); + return false; + } + } + _pin = strdup(pin); + if(_pin == NULL){ + log_e("Failed to strdup PIN"); + return false; + } + } + return true; +} + +int PPPClass::RSSI() const +{ + if(_dce == NULL){ + return -1; + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return -1; + } + + int rssi, ber; + esp_err_t err = esp_modem_get_signal_quality(_dce, rssi, ber); + if (err != ESP_OK) { + // log_e("esp_modem_get_signal_quality failed with %d %s", err, esp_err_to_name(err)); + return -1; + } + return rssi; +} + +int PPPClass::BER() const +{ + if(_dce == NULL){ + return -1; + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return -1; + } + + int rssi, ber; + esp_err_t err = esp_modem_get_signal_quality(_dce, rssi, ber); + if (err != ESP_OK) { + // log_e("esp_modem_get_signal_quality failed with %d %s", err, esp_err_to_name(err)); + return -1; + } + return ber; +} + +String PPPClass::IMSI() const +{ + if(_dce == NULL){ + return String(); + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return String(); + } + + char imsi[32]; + esp_err_t err = esp_modem_get_imsi(_dce, (std::string&)imsi); + if (err != ESP_OK) { + log_e("esp_modem_get_imsi failed with %d %s", err, esp_err_to_name(err)); + return String(); + } + + return String(imsi); +} + +String PPPClass::IMEI() const +{ + if(_dce == NULL){ + return String(); + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return String(); + } + + char imei[32]; + esp_err_t err = esp_modem_get_imei(_dce, (std::string&)imei); + if (err != ESP_OK) { + log_e("esp_modem_get_imei failed with %d %s", err, esp_err_to_name(err)); + return String(); + } + + return String(imei); +} + +String PPPClass::moduleName() const +{ + if(_dce == NULL){ + return String(); + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return String(); + } + + char name[32]; + esp_err_t err = esp_modem_get_module_name(_dce, (std::string&)name); + if (err != ESP_OK) { + log_e("esp_modem_get_module_name failed with %d %s", err, esp_err_to_name(err)); + return String(); + } + + return String(name); +} + +String PPPClass::operatorName() const +{ + if(_dce == NULL){ + return String(); + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return String(); + } + + char oper[32]; + int act = 0; + esp_err_t err = esp_modem_get_operator_name(_dce, (std::string&)oper, act); + if (err != ESP_OK) { + log_e("esp_modem_get_operator_name failed with %d %s", err, esp_err_to_name(err)); + return String(); + } + + return String(oper); +} + +int PPPClass::networkMode() const +{ + if(_dce == NULL){ + return -1; + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return -1; + } + + int m = 0; + esp_err_t err = esp_modem_get_network_system_mode(_dce, m); + if (err != ESP_OK) { + log_e("esp_modem_get_network_system_mode failed with %d %s", err, esp_err_to_name(err)); + return -1; + } + return m; +} + +int PPPClass::radioState() const +{ + if(_dce == NULL){ + return -1; + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return -1; + } + + int m = 0; + esp_err_t err = esp_modem_get_radio_state(_dce, m); + if (err != ESP_OK) { + // log_e("esp_modem_get_radio_state failed with %d %s", err, esp_err_to_name(err)); + return -1; + } + return m; +} + +bool PPPClass::powerDown(){ + if(_dce == NULL){ + return false; + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return false; + } + + esp_err_t err = esp_modem_power_down(_dce); + if (err != ESP_OK) { + log_e("esp_modem_power_down failed with %d %s", err, esp_err_to_name(err)); + return false; + } + return true; +} + +bool PPPClass::reset(){ + if(_dce == NULL){ + return false; + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return false; + } + + esp_err_t err = esp_modem_reset(_dce); + if (err != ESP_OK) { + log_e("esp_modem_reset failed with %d %s", err, esp_err_to_name(err)); + return false; + } + return true; +} + +bool PPPClass::storeProfile(){ + if(_dce == NULL){ + return false; + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return false; + } + + esp_err_t err = esp_modem_store_profile(_dce); + if (err != ESP_OK) { + log_e("esp_modem_store_profile failed with %d %s", err, esp_err_to_name(err)); + return false; + } + return true; +} + +bool PPPClass::setBaudrate(int baudrate) { + if(_dce == NULL){ + return false; + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return false; + } + + esp_err_t err = esp_modem_set_baud(_dce, baudrate); + if (err != ESP_OK) { + log_e("esp_modem_set_baud failed with %d %s", err, esp_err_to_name(err)); + return false; + } + + uint32_t sclk_freq; + err = uart_get_sclk_freq(UART_SCLK_DEFAULT, &sclk_freq); + if(err != ESP_OK){ + log_e("uart_get_sclk_freq failed with %d %s", err, esp_err_to_name(err)); + return false; + } + uart_ll_set_baudrate(UART_LL_GET_HW(_uart_num), (uint32_t)baudrate, sclk_freq); + + return true; +} + +bool PPPClass::sms(const char * num, const char * message) { + if(_dce == NULL){ + return false; + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return false; + } + + for(int i=0; i 0x39)){ + log_e("Bad character '%c' in SMS Number. Should be only digits and +, # or *", num[i]); + return false; + } + } + + esp_err_t err = esp_modem_sms_txt_mode(_dce, true); + if (err != ESP_OK) { + log_e("Setting text mode failed %d %s", err, esp_err_to_name(err)); + return false; + } + + err = esp_modem_sms_character_set(_dce); + if (err != ESP_OK) { + log_e("Setting GSM character set failed %d %s", err, esp_err_to_name(err)); + return false; + } + + err = _esp_modem_send_sms(_dce, num, message); + if (err != ESP_OK) { + log_e("esp_modem_send_sms() failed with %d %s", err, esp_err_to_name(err)); + return false; + } + return true; +} + +String PPPClass::cmd(const char * at_command, int timeout){ + if(_dce == NULL){ + return String(); + } + + if(_mode == ESP_MODEM_MODE_DATA){ + log_e("Wrong modem mode. Should be ESP_MODEM_MODE_COMMAND"); + return String(); + } + char out[128] = {0}; + esp_err_t err = _esp_modem_at(_dce, at_command, out, timeout); + if (err != ESP_OK) { + log_e("esp_modem_at failed %d %s", err, esp_err_to_name(err)); + return String(); + } + return String(out); +} + +size_t PPPClass::printDriverInfo(Print & out) const { + size_t bytes = 0; + if(_dce == NULL || _mode == ESP_MODEM_MODE_DATA){ + return bytes; + } + if(attached()){ + bytes += out.print(","); + bytes += out.print(operatorName()); + } + bytes += out.print(",RSSI:"); + bytes += out.print(RSSI()); + bytes += out.print(",BER:"); + bytes += out.print(BER()); + return bytes; +} + +PPPClass PPP; + +#endif /* CONFIG_LWIP_PPP_SUPPORT */ diff --git a/libraries/PPP/src/PPP.h b/libraries/PPP/src/PPP.h new file mode 100644 index 00000000000..97ce62a5945 --- /dev/null +++ b/libraries/PPP/src/PPP.h @@ -0,0 +1,107 @@ +#pragma once + +#include "sdkconfig.h" +#if CONFIG_LWIP_PPP_SUPPORT +#include "Network.h" +#include "esp_modem_c_api_types.h" + +typedef enum { + PPP_MODEM_GENERIC = ESP_MODEM_DCE_GENETIC, + PPP_MODEM_SIM7600 = ESP_MODEM_DCE_SIM7600, + PPP_MODEM_SIM7070 = ESP_MODEM_DCE_SIM7070, + PPP_MODEM_SIM7000 = ESP_MODEM_DCE_SIM7000, + PPP_MODEM_BG96 = ESP_MODEM_DCE_BG96, + PPP_MODEM_SIM800 = ESP_MODEM_DCE_SIM800, +#if CONFIG_ESP_MODEM_ADD_CUSTOM_MODULE + PPP_MODEM_CUSTOM = ESP_MODEM_DCE_CUSTOM, +#endif + PPP_MODEM_MAX +} ppp_modem_model_t; + +class PPPClass: public NetworkInterface { + public: + PPPClass(); + ~PPPClass(); + + bool begin(ppp_modem_model_t model, uint8_t uart_num=1, int baud_rate=115200); + void end(); + + // Required for connecting to internet + bool setApn(const char * apn); + + // Required only if the SIM card is protected by PIN + bool setPin(const char * pin); + + // If the modem supports hardware flow control, it's best to use it + bool setPins(int8_t tx, int8_t rx, int8_t rts=-1, int8_t cts=-1, esp_modem_flow_ctrl_t flow_ctrl=ESP_MODEM_FLOW_CONTROL_NONE); + + // Using the reset pin of the module ensures that proper communication can be achieved + void setResetPin(int8_t rst, bool active_low=true); + + // Modem DCE APIs + int RSSI() const; + int BER() const; + String IMSI() const; + String IMEI() const; + String moduleName() const; // modem module name + String operatorName() const; // network operator name + int networkMode() const; // network type (GSM, LTE, etc.) + int radioState() const; // 0:minimal, 1:full + bool attached() const; // true is attached to network + bool sync() const; // true if responds to 'AT' + + // Switch the communication mode + bool mode(esp_modem_dce_mode_t m); + esp_modem_dce_mode_t mode() const { return _mode; } + + // Change temporary the baud rate of communication + bool setBaudrate(int baudrate); + + // Sens SMS message to a number + bool sms(const char * num, const char * message); + bool sms(String num, String message){ + return sms(num.c_str(), message.c_str()); + } + + // Send AT command with timeout in milliseconds + String cmd(const char * at_command, int timeout); + String cmd(String at_command, int timeout){ + return cmd(at_command.c_str(), timeout); + } + + // untested + bool powerDown(); + bool reset(); + bool storeProfile(); + + esp_modem_dce_t * handle() const; + + protected: + size_t printDriverInfo(Print & out) const; + + public: + void _onPppEvent(int32_t event_id, void* event_data); + void _onPppArduinoEvent(arduino_event_id_t event, arduino_event_info_t info); + + private: + esp_modem_dce_t *_dce; + int8_t _pin_tx; + int8_t _pin_rx; + int8_t _pin_rts; + int8_t _pin_cts; + esp_modem_flow_ctrl_t _flow_ctrl; + int8_t _pin_rst; + bool _pin_rst_act_low; + const char * _pin; + const char * _apn; + int _rx_buffer_size; + int _tx_buffer_size; + esp_modem_dce_mode_t _mode; + uint8_t _uart_num; + + static bool pppDetachBus(void * bus_pointer); +}; + +extern PPPClass PPP; + +#endif /* CONFIG_LWIP_PPP_SUPPORT */ diff --git a/libraries/PPP/src/ppp.c b/libraries/PPP/src/ppp.c new file mode 100644 index 00000000000..fafd6cc4525 --- /dev/null +++ b/libraries/PPP/src/ppp.c @@ -0,0 +1,28 @@ +#include "sdkconfig.h" +#if CONFIG_LWIP_PPP_SUPPORT +#include "esp_modem_api.h" + +esp_err_t _esp_modem_at(esp_modem_dce_t *dce_wrap, const char *at, char *p_out, int timeout){ + return esp_modem_at(dce_wrap, at, p_out, timeout); +} + +esp_err_t _esp_modem_send_sms(esp_modem_dce_t *dce_wrap, const char *number, const char *message){ + return esp_modem_send_sms(dce_wrap, number, message); +} + +esp_err_t _esp_modem_set_pin(esp_modem_dce_t *dce_wrap, const char *pin){ + return esp_modem_set_pin(dce_wrap, pin); +} + +esp_err_t _esp_modem_at_raw(esp_modem_dce_t *dce_wrap, const char *cmd, char *p_out, const char *pass, const char *fail, int timeout){ + return esp_modem_at_raw(dce_wrap, cmd, p_out, pass, fail, timeout); +} + +esp_err_t _esp_modem_set_operator(esp_modem_dce_t *dce_wrap, int mode, int format, const char *oper){ + return esp_modem_set_operator(dce_wrap, mode, format, oper); +} + +esp_err_t _esp_modem_set_network_bands(esp_modem_dce_t *dce_wrap, const char *mode, const int *bands, int size){ + return esp_modem_set_network_bands(dce_wrap, mode, bands, size); +} +#endif // CONFIG_LWIP_PPP_SUPPORT diff --git a/package/package_esp32_index.template.json b/package/package_esp32_index.template.json index c8d48f1261e..ced6417798b 100644 --- a/package/package_esp32_index.template.json +++ b/package/package_esp32_index.template.json @@ -42,7 +42,7 @@ { "packager": "esp32", "name": "esp32-arduino-libs", - "version": "idf-release_v5.1-d23b7a0361" + "version": "idf--d23b7a0361" }, { "packager": "esp32", @@ -105,63 +105,63 @@ "tools": [ { "name": "esp32-arduino-libs", - "version": "idf-release_v5.1-d23b7a0361", + "version": "idf--d23b7a0361", "systems": [ { "host": "i686-mingw32", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799", - "archiveFileName": "esp32-arduino-libs-0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799.zip", - "checksum": "SHA-256:dae6b3bc63778977bf08a372630ba57dff217e9674fea85964c95da9f738f6f6", - "size": "359464912" + "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/5daaf1a26c12b495975a367cf2c73b86ddee5d31", + "archiveFileName": "esp32-arduino-libs-5daaf1a26c12b495975a367cf2c73b86ddee5d31.zip", + "checksum": "SHA-256:6fe9a5643057449bbbe850cd0e7217f3f6753adc8d5da2807f0c071a1ccb44f1", + "size": "372257794" }, { "host": "x86_64-mingw32", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799", - "archiveFileName": "esp32-arduino-libs-0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799.zip", - "checksum": "SHA-256:dae6b3bc63778977bf08a372630ba57dff217e9674fea85964c95da9f738f6f6", - "size": "359464912" + "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/5daaf1a26c12b495975a367cf2c73b86ddee5d31", + "archiveFileName": "esp32-arduino-libs-5daaf1a26c12b495975a367cf2c73b86ddee5d31.zip", + "checksum": "SHA-256:6fe9a5643057449bbbe850cd0e7217f3f6753adc8d5da2807f0c071a1ccb44f1", + "size": "372257794" }, { "host": "arm64-apple-darwin", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799", - "archiveFileName": "esp32-arduino-libs-0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799.zip", - "checksum": "SHA-256:dae6b3bc63778977bf08a372630ba57dff217e9674fea85964c95da9f738f6f6", - "size": "359464912" + "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/5daaf1a26c12b495975a367cf2c73b86ddee5d31", + "archiveFileName": "esp32-arduino-libs-5daaf1a26c12b495975a367cf2c73b86ddee5d31.zip", + "checksum": "SHA-256:6fe9a5643057449bbbe850cd0e7217f3f6753adc8d5da2807f0c071a1ccb44f1", + "size": "372257794" }, { "host": "x86_64-apple-darwin", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799", - "archiveFileName": "esp32-arduino-libs-0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799.zip", - "checksum": "SHA-256:dae6b3bc63778977bf08a372630ba57dff217e9674fea85964c95da9f738f6f6", - "size": "359464912" + "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/5daaf1a26c12b495975a367cf2c73b86ddee5d31", + "archiveFileName": "esp32-arduino-libs-5daaf1a26c12b495975a367cf2c73b86ddee5d31.zip", + "checksum": "SHA-256:6fe9a5643057449bbbe850cd0e7217f3f6753adc8d5da2807f0c071a1ccb44f1", + "size": "372257794" }, { "host": "x86_64-pc-linux-gnu", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799", - "archiveFileName": "esp32-arduino-libs-0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799.zip", - "checksum": "SHA-256:dae6b3bc63778977bf08a372630ba57dff217e9674fea85964c95da9f738f6f6", - "size": "359464912" + "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/5daaf1a26c12b495975a367cf2c73b86ddee5d31", + "archiveFileName": "esp32-arduino-libs-5daaf1a26c12b495975a367cf2c73b86ddee5d31.zip", + "checksum": "SHA-256:6fe9a5643057449bbbe850cd0e7217f3f6753adc8d5da2807f0c071a1ccb44f1", + "size": "372257794" }, { "host": "i686-pc-linux-gnu", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799", - "archiveFileName": "esp32-arduino-libs-0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799.zip", - "checksum": "SHA-256:dae6b3bc63778977bf08a372630ba57dff217e9674fea85964c95da9f738f6f6", - "size": "359464912" + "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/5daaf1a26c12b495975a367cf2c73b86ddee5d31", + "archiveFileName": "esp32-arduino-libs-5daaf1a26c12b495975a367cf2c73b86ddee5d31.zip", + "checksum": "SHA-256:6fe9a5643057449bbbe850cd0e7217f3f6753adc8d5da2807f0c071a1ccb44f1", + "size": "372257794" }, { "host": "aarch64-linux-gnu", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799", - "archiveFileName": "esp32-arduino-libs-0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799.zip", - "checksum": "SHA-256:dae6b3bc63778977bf08a372630ba57dff217e9674fea85964c95da9f738f6f6", - "size": "359464912" + "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/5daaf1a26c12b495975a367cf2c73b86ddee5d31", + "archiveFileName": "esp32-arduino-libs-5daaf1a26c12b495975a367cf2c73b86ddee5d31.zip", + "checksum": "SHA-256:6fe9a5643057449bbbe850cd0e7217f3f6753adc8d5da2807f0c071a1ccb44f1", + "size": "372257794" }, { "host": "arm-linux-gnueabihf", - "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799", - "archiveFileName": "esp32-arduino-libs-0dbfb946a0af0e10f9caa0a22aa1ee4b5bd79799.zip", - "checksum": "SHA-256:dae6b3bc63778977bf08a372630ba57dff217e9674fea85964c95da9f738f6f6", - "size": "359464912" + "url": "https://codeload.github.com/espressif/esp32-arduino-libs/zip/5daaf1a26c12b495975a367cf2c73b86ddee5d31", + "archiveFileName": "esp32-arduino-libs-5daaf1a26c12b495975a367cf2c73b86ddee5d31.zip", + "checksum": "SHA-256:6fe9a5643057449bbbe850cd0e7217f3f6753adc8d5da2807f0c071a1ccb44f1", + "size": "372257794" } ] },